linux下多线程同步机制(信号量的使用大全)

修改:


在互斥锁的例子上 添加一个死锁的概念,可以设置resource属性,然后可以对其进行二次加锁
===========================================================================
旅客与出租车的案列:
pthread_cond_t taxiCond;

// 同步锁
pthread_mutex_t taxiMutex;

// 旅客到达等待出租车
void * traveler_arrive(void * name) {
cout<< ” Traveler: ” <<(char *)name<< ” needs a taxi now! ” <pthread_mutex_lock(&taxiMutex);
pthread_cond_wait (&taxiCond, &taxtMutex);
pthread_mutex_unlock (&taxtMutex);
cout<< ” Traveler: ” << (char *)name << ” now got a taxi! ” <pthread_exit( (void *)0 );
}

// 出租车到达
void * taxi_arrive(void *name) {
cout<< ” Taxi ” <<(char *)name<< ” arrives. ” <pthread_cond_signal(&taxtCond);
pthread_exit( (void *)0 );
}

void main() {
// 初始化
taxtCond= PTHREAD_COND_INITIALIZER;
taxtMutex= PTHREAD_MUTEX_INITIALIZER;
pthread_t thread;
pthread_attr_t threadAttr;
pthread_attr_init(&threadAttr);

pthread_create(&thread, & threadAttr, taxt_arrive, (void *)( ” Jack ” ));
sleep(1);
pthread_create(&thread, &threadAttr, traveler_arrive, (void *)( ” Susan ” ));
sleep(1);
pthread_create(&thread, &threadAttr, taxi_arrive, (void *)( ” Mike ” ));
sleep(1);

return 0;
}


============================================================================
// 提示出租车到达的条件变量
pthread_cond_t taxiCond;

// 同步锁
pthread_mutex_t taxiMutex;

// 旅客人数,初始为 0
int travelerCount=0;

// 旅客到达等待出租车
void * traveler_arrive(void * name) {
cout<< ” Traveler: ” <<(char *)name<< ” needs a taxi now! ” <pthread_mutex_lock(&taxiMutex);

// 提示旅客人数增加
travelerCount++;
pthread_cond_wait (&taxiCond, &taxiMutex);
pthread_mutex_unlock (&taxiMutex);
cout<< ” Traveler: ” << (char *)name << ” now got a taxi! ” <pthread_exit( (void *)0 );
}

// 出租车到达
void * taxi_arrive(void *name)
{
cout<< ” Taxi ” <<(char *)name<< ” arrives. ” <
while(true)
{
pthread_mutex_lock(&taxiMutex);

// 当发现已经有旅客在等待时,才触发条件变量
if(travelerCount>0)
{
pthread_cond_signal(&taxtCond);
pthread_mutex_unlock (&taxiMutex);
break;
}
pthread_mutex_unlock (&taxiMutex);
}

pthread_exit( (void *)0 );
}


====================================信号量(案列分析)===========================================


#include
#include
#include
#include
#include
int number; // 被保护的全局变量
se

m_t sem_id;
void* thread_one_fun(void *arg)
{
sem_wait(&sem_id);
printf("thread_one have the semaphore\n");
number++;
printf("number = %d\n",number);
sem_post(&sem_id);
}
void* thread_two_fun(void *arg)
{
sem_wait(&sem_id);
printf("thread_two have the semaphore \n");
number--;
printf("number = %d\n",number);
sem_post(&sem_id);
}
int main(int argc,char *argv[])
{
number = 1;
pthread_t id1, id2;
sem_init(&sem_id, 0, 1);
pthread_create(&id1,NULL,thread_one_fun, NULL);
pthread_create(&id2,NULL,thread_two_fun, NULL);
pthread_join(id1,NULL);
pthread_join(id2,NULL);
printf("main,,,\n");
return 0;
}


=====================================创建线程的参数详解==========================
(总原则,声明顺序与调用顺序一致。)步骤:

先抹掉左边第一个类型(void*)这意味着右边一整坨东东的最终返回值/类型是任意类型指针,
剩下:(*start_routine) (void *)

从变量名开始分拆(优先向左看):

start_routine

(向左看)紧挨start_routine的操作符是*,说明start_routine是一个指针变量。

(向左看)紧挨*start_routine的操作符是(),说明*start_routine指向某种符号(可以是数组名或者函数等等)
而非某个储存空间。

(向左看)没有了,向右看,紧挨(*start_routine) 是一个(),意味着*start_routine指向一个函数首地址,
换句话说(*start_routine) (XXXXXX),表示调用一个函数,函数的形式为XXX(XXXX);

再看这个()里的东西:void*,意味着函数的参数是任意类型指针即函数的形式为XXX(void* a);之类。

再向右看,没了。那么这个函数的返回值就是第一步所抹掉的类型:void*

那么start_routine是一个指针变量,其内容储存一个函数的入口地址。这个变量可以用来调用这个函数。
(所谓的函数指针)函数原型如下:

void* F(void* a);//函数名F,形参名a都是可以任意的。

可以:start_routine=F;

那么(*start_routine)("sdf");与F("sdf");意思就是一样的,都是调用F函数。

void *(*start_routine) (void *)作为函数的参数,意味着你可以自定义一个类似于以上F函数一样形式的函数,
作为回调,当线程被创建时由系统调用。这个时候,系统就可以去调用一个他并不知道的函数,这个函数由你来决定是什么,
怎么运作,用来干什么。系统不必了解这些细节,只管调用就OK了。


===============================信号量简单案列======================================
#include

#include

#include



sem_t sem_a;

void *task1();



int main(void)

{

int ret=0;

pthread_t thrd1;

pthread_t thrd2;

sem_init(&sem_a,0,1);

ret=pthread_create(&thrd1,NULL,task1,NULL);

ret=pthread_create(&

thrd2,NULL,task1,NULL);

pthread_join(thrd1,NULL);

pthread_join(thrd2,NULL);
}



void *task1()

{

int sval = 0;

sem_wait(&sem_a);

sleep(5);

sem_getvalue(&sem_a,&sval);

printf("sem value = %d\n",sval);

sem_post(&sem_a);

}

==============================信号量=====================================
#include
#include
#include
#include
#include

typedef struct __Buf {
int *buf; // 缓冲区
int n; // 最大缓冲区
int head; // 缓冲区头
int tail; // 缓冲区尾
sem_t items; // 锁定对不存在项目的缓冲区进行操作的消费者
sem_t slots; // 锁定对已满缓冲区进行操作的生产者
sem_t mutex; // 确保同时只能有一个消费者或生产者对缓存区进行操作
} Buf;

// 声明缓冲区
Buf g_buf;

// 生产者插入项目
void insert(Buf *b, int item) {
sem_wait(&b->slots);
sem_wait(&b->mutex);
// 插入数据
b->buf[(++b->tail)%b->n] = item;
sem_post(&b->mutex);
// post等价於把信号量加一,令消费者能对缓冲区操作(说明缓冲区状态为非空)
sem_post(&b->items);
}

// 生产者线程
void *manufacturer(void *) {
int i=0;
for(i=0; i<100; ++i) {
insert(&g_buf, i);
}
return 0;
}

// 消费者获取项目
int get(Buf *b) {
int item;
sem_wait(&b->items);
sem_wait(&b->mutex);
// 获取数据(意义上是删除了缓冲区中一个项目)
item = b->buf[(++b->head)%b->n];
sem_post(&b->mutex);
// post等价于把信号量加一,令生产者能对缓冲区操作(说明缓冲区状态为未满)
sem_post(&b->slots);
return item;
}

// 消费者线程
void *consumer(void *) {
int i=0, data;
for(i=0; i<100; ++i) {
data = get(&g_buf);
printf("consumer: %d\n", data);
// 消费者睡300ms, 测试一下看看生产者会不会把缓冲区溢出
usleep(1000*300);
}
return 0;
}

int main() {
pthread_t tid_man, tid_con;

// 设置缓冲区
g_buf.n = 5;
g_buf.buf = (int *)malloc(g_buf.n*sizeof(int));
sem_init(&g_buf.mutex, 0, 1);
sem_init(&g_buf.slots, 0, g_buf.n); // g_buf.n也就是允许插入的数量
sem_init(&g_buf.items, 0, 0);
g_buf.head = -1;
g_buf.tail = -1;

// 创建生产者与消费者线程
pthread_create(&tid_man, 0, manufacturer, 0);
pthread_create(&tid_con, 0, consumer, 0);

// 释放已申请的资源
pthread_join(tid_man, 0);
pthread_join(tid_con, 0);
sem_destroy(&g_buf.items);
sem_destroy(&g_buf.slots);
sem_destroy(&g_buf.mutex);

return 0;
}



===================================================================================
#include
#include
#include <

stdio.h>

#define BUFFER_SIZE 10//缓冲区大小为10
char *buffer;
sem_t mutex,empty,full;//三个信号量,互斥信号量mutex,技术信号量empty和full
int x,y;//生产者和消费者在buffer中下标
void output()//输出buffer数组
{
int i;
for(i=0;i{
printf("%c",buffer[i]);
printf(" ");
}
printf("\n");
}
void *produce()//生产者函数
{
int j;
j=0;
do
{
sem_wait(&empty);//buffer有空余部分,可以生产,并减一
sem_wait(&mutex);//形成互斥访问,只能一个线程生产
printf("%lu%s%d%s",pthread_self(),"^^^^^",j,"^^^^^ ");//输出当前线程的id号,以及正在执行的次数
buffer[(x++)%BUFFER_SIZE]='A';//生产就赋值A
output();//输出buffer
j++;
sem_post(&mutex);//取消互斥
sem_post(&full);//生成完毕,增加一个可以消费量。
}while (j!=30);//每个线程可以做30次
}
void *consume()//消费者函数
{
int j;
j=0;
do
{
sem_wait(&full);//可以消费的量减一
sem_wait(&mutex);//互斥访问,只能一个线程消费
printf("%lu%s%d%s",pthread_self(),"*****",j,"***** ");
buffer[(y++)%BUFFER_SIZE]='B';//消费时,赋值为B
output();//输出buffer值
j++;
sem_post(&mutex);//取消互斥,其他线程可以消费
sem_post(&empty);//空余量加一
}while (j!=30);//每个线程可以消费30次
}

int main()
{
int i;
x=0;
y=0;
buffer=(char*)malloc(BUFFER_SIZE*sizeof(char*));
for(i=0;i{
buffer[i]='N';
}
//semaphore
sem_init(&mutex,1,1);//初始化互斥信号量mutex为1
sem_init(&empty,0,BUFFER_SIZE);//初始化计数信号量empty为BUFFER_SIZE
sem_init(&full,0,0);//初始化计数信号量full为0
//multipthread
pthread_t tid[10];
pthread_attr_t attr;
pthread_attr_init(&attr);
//创建5个生产者线程和5个消费者线程
for(i=0;i<5;i++)
{
pthread_create(&tid[i],&attr,consume,NULL);
pthread_create(&tid[i+5],&attr,produce,NULL);
}
//让每个线程在主线程main执行前全部执行完毕。
for(i=0;i<10;i++)
{
pthread_join(tid[i],NULL);
}
return 0;
}

相关文档
最新文档