如何理解条件变量&&Posix信号量

条件变量

为什么要有条件变量??
当一个线程互斥的访问某个变量时,这个线程在其他线程改变状态之前什么也不能干,只能等待
比如说,一个线程访问队列时,发现队列为空,那么就会一直等待,直到有节点添入该队列,这个时候就应该使用条件变量,告诉该线程你可以去做其他的事情不用一直等,如果有你想要的我会通知你
1. pthread_cond_t cond;------------------------创建条件变量
2. pthread_cond_init(&cond, NULL);-------------初始化 条件变量
3. pthread_cond_wait(&cond, &mutex);-----------在cond这个条件变量上等待,
                                                // 阻塞,将mutex置成1,    
                                                // 返回,将mutex恢复成原样
4. pthread_cond_signal(&cond);-----------------当有资源可用时传回一个信号去唤醒等待
5. pthread_cond_destroy(&cond);----------------销毁条件变量

wait为什么要有互斥量?

在某些情况下,如果某个条件变量一直得不到满足,那么该条件变量就会一直等待,这时候需要有一个线程来改变共享变量,当条件变量得到满足时,还需要通知等待在条件变量上的线程,告诉它你要的资源已经有了,快来访问吧~

使用规范:
{
     pthread_mutex_lock(&mutex);
     while ( 条件不满足 )    //  while 防止假唤醒
        pthread_cond_wait(&cond, &mutex); 
     修改条件
     pthread_mutex_unlock(&mutex);
}
//给条件变量发送信号
 {
    pthread_mutex_lock(&mutex);
    pthread_cond_signal(&cond);    // 唤醒等待,如果没有线程等在wait,signal就丢失
    pthread_mutex_unlock(&mutex);
}
wait和unlock必须是原子操作,否则可能会导致wait错过原本应该等待的信号,那么在等待的线程就会阻塞。


基于条件变量和互斥量编写的生产者消费者模型(使用链表编写)

//////////////////////////////////////////////////////////我是分割线//////////////////////////////////////////////////////
 1#include<stdio.h>
  2 #include<pthread.h>
  3 #include<stdlib.h>

  5 typedef struct _Node{
  6     int data;
  7     struct _Node *next;
  8 }node_t,*node_p,**node_pp;
  9 //加锁
10 node_p head;
---------------------------------------------------------------------------------------------------------------------------------------
12 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//条件变量
13
14 static node_p alloc_node(int _d,node_p _n)
15 {
16     node_p tmp = (node_p)malloc(sizeof(node_t));
17     if(!tmp)
18     {
19         perror("malloc");
20         exit(1);
21     }
22
23     tmp->data = _d;
24     tmp->next = _n;
25     return tmp;
26 }
---------------------------------------------------------------------------------------------------------------------------------------
27static void freeNode(node_p tmp)
28 {
29     if(tmp)
30     {
31         free(tmp);
32     }
33 }
---------------------------------------------------------------------------------------------------------------------------------------
34 int isEmpty(node_p _h)
35 {
36     return _h->next==NULL?1:0;
37 }
---------------------------------------------------------------------------------------------------------------------------------------
38 void initList(node_pp _hp)
39 {
40     *_hp = alloc_node(0,NULL);
41 }
---------------------------------------------------------------------------------------------------------------------------------------
43 void pushHead(node_p _h,int _d)
44 {
45     node_p tmp = alloc_node(_d,NULL);
46
47     tmp->next = _h->next;
48     _h->next = tmp;
49 }
---------------------------------------------------------------------------------------------------------------------------------------
51void popHead(node_p _h,int * _outdata)
52 {
53     if(!isEmpty(_h))
54     {
55         node_p tmp = _h->next;
56         _h->next = tmp->next;
57         *_outdata = tmp->data;
58         freeNode(tmp);
59         tmp = NULL;
60     }
61 }
---------------------------------------------------------------------------------------------------------------------------------------
62 void destroyList(node_p _h)
63 {
64     int data;
65     while(!isEmpty(_h))
66     {
67         popHead(_h,&data);
68     }
69     freeNode(_h);//释放最后一个
70 }
---------------------------------------------------------------------------------------------------------------------------------------
71void showList(node_p _h)
72 {
73     node_p start = _h->next;
74     while(start)
75     {
76         printf("%d  ",start->data);
77         start = start->next;
78     }
79     printf("\n");
80 }
-----------------------------------------------------------消费者----------------------------------------------------------------------
82void* consume(void* arg)
83 {
84     pthread_mutex_t *lockp = (pthread_mutex_t*)arg;
85     int data = 0;
86     while(1)
87     {
88         //data = -1;
89         pthread_mutex_lock(lockp);
90         //互斥性检测
91         while(isEmpty(head))
92         {
93             pthread_cond_wait(&cond, lockp);//保证当前进程休眠,所以要释放锁,休眠之后还要能被唤醒
94         }
95         popHead(head,&data);
96
97         printf("consumer done ,%d \n",data);
98         pthread_mutex_unlock(lockp);
99     }
100 }
--------------------------------------------------------------------生产者------------------------------------------------------
        void* produce(void* arg)
102 {
103     pthread_mutex_t *lockp = (pthread_mutex_t*)arg;
104     int data = 0;
105     while(1)
106     {
107         pthread_mutex_lock(lockp);
108         data = rand()%1234;
109
110         pushHead(head,data);
111         printf("producer done ,%d \n",data);
112         pthread_mutex_unlock(lockp);
113         pthread_cond_signal(&cond);
114         sleep(1);
115     }
116 }
----------------------------------------------------------------------主函数------------------------------------------------------
int main()
 {
     pthread_mutex_t  lock ;
     pthread_mutex_init(&lock,NULL);
     initList(&head);
     pthread_create(&consumer,NULL,consume,(pthread_mutex_t*)&lock);
    pthread_create(&producer,NULL,produce,(pthread_mutex_t*)&lock);

     pthread_join(consumer,NULL);
    pthread_join(producer,NULL);

     destroyList(head);
    pthread_mutex_destroy(&lock);
     pthread_cond_destroy(&cond);
}

运行结果:


Posix信号量

该信号量与SystemV信号量的作用类似,但该信号量用于线程间同步

sem_t sem;    
初始化信号量
    int sem_init(sem_t *sem,
                 int pshared,        // 0 表示本进程内多个线程间的同步互斥
                 unsigned int value) // 设置初值
// 销毁信号量
    int sem_destroy(sem_t *sem);
  
等待信号量(类似于P操作)
    int sem_wait(sem_t *sem);-----------------将信号量的值减一
释放信号量(类似于V操作)
    int sem_post(sem_t *sem);-----------------将信号量的值加一


猜你喜欢

转载自blog.csdn.net/qq_36474990/article/details/80288612