一.概念:
- 同步:是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問。在大多數情況下,同步已經實現了互斥,特別是所有寫入資源的情況必定是互斥的。少數情況是指可以允許多個訪問者同時訪問資源。
- 通俗來講,互斥只是實現了安全問題,而有的時候,它並不高效,所以在此引出了
條件變量
,它可以用來實現高效。 - 互斥鎖和條件變量分別用來實現互斥和同步,是一對黃金搭檔。
二.涉及的函數
創建一個條件變量有兩種方式
定義一個全局變量如下:
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
使用初始化函數:
條件變量的銷燬函數
- 條件變量等待函數
條件變量有兩個等待函數。二者的區別就在於pthread_cond_timedwait()比pthread_cond_wait()函數多了一個參數abstime,此參數可以設定等待超時,如果達到abstime所指定的時刻,仍然沒有別的線程來喚醒當前線程,就返回ETIMEDOUT。
pthread_cond_wait在阻塞式等待,這個函數做了以下三步操作:
1.釋放Muxtex
2.阻塞等待
3.當被喚醒時,重新獲得Mutex並返回 - 條件變量喚醒函數
有兩個喚醒函數,區別是:
pthread_cond_signal喚醒的是某個Condition Variable上等待的另一個線程,也可以調用
pthread_cond_broadcast喚醒在這個Condition Variadle上等待的所有線程
##三.代碼演示:
下列程序演示了一個生產者-消費者的例子,表現同步互斥的效果 - 以下代碼是隻加了互斥鎖的代碼,在消費者線程中加入了
sleep(100);
以達到增強生產者線程的競爭力的效果;代碼以及效果圖如下:
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<pthread.h>
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
typedef struct _node
{
struct _node* _next;
int data;
}_node,*_node_p,**_node_pp;
_node_p alloc(int data)
{
_node_p _node=(_node_p)malloc(sizeof(data));
if(_node==NULL)
{
perror("malloc");
exit (0);
}
_node->data=data;
_node->_next=NULL;
return _node;
}
void delete_node(_node_p temp)
{
if(!temp)
free(temp);
}
static int is_empty(_node_p _h)
{
if(NULL==_h->_next)
{
return 1;
}
return 0;
}
void show_List(_node_p _h)
{
assert(_h);
_node_p temp=_h->_next;
while(NULL!=temp)
{
printf("%d ",temp->data);
temp=temp->_next;
}
printf("\n");
}
void pop_List(_node_p _h,int* _o)
{
if(!is_empty(_h))
{
_node_p temp=_h->_next;
_h->_next=temp->_next;
*_o=temp->data;
delete_node(temp);
}
}
void init_List(_node_pp _h)
{
*_h=alloc(0);
}
void destory_List(_node_p _h)
{
int data;
while(is_empty(_h));
{
pop_List(_h,&data);
}
delete_node(_h);
}
void push_List(_node_p _h,int data)
{
_node_p Newnode=alloc(data);
Newnode->_next=_h->_next;
_h->_next=Newnode;
}
static void* consumer(void* _h)
{
_node_p head=(_node_p) _h;
for(;;)
{
pthread_mutex_lock(&lock);
int data=rand()%1000;
pop_List(head,&data);
pthread_mutex_unlock(&lock);
printf("consumer:%d\n",data);
sleep(100);
}
}
static void* producter(void* _h)
{
_node_p head=(_node_p) _h;
for(;;)
{
pthread_mutex_lock(&lock);
int i=rand()%1000;
push_List(head,i);
pthread_mutex_unlock(&lock);
printf("producter:%d\n",i);
sleep(1);
}
}
int main()
{
_node_p head=NULL;
init_List(&head);
pthread_t tid1;
pthread_t tid2;
pthread_create(&tid1,NULL,*consumer,head);
pthread_create(&tid2,NULL,*producter,head);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_cond_destroy(&cond);
return 0;
}
結果圖如下:
出現了只生產不消費的情況。
要解決如上問題:則需要時生產者和消費者同步起來:使用條件變量.
- 使用條件變量解決上述問題:
代碼如下:
static void* consumer(void* _h)
{
_node_p head=(_node_p) _h;
for(;;)
{
pthread_mutex_lock(&lock);
int data=rand()%1000;
while(is_empty(head))
{
pthread_cond_wait(&cond,&lock);
}
pop_List(head,&data);
pthread_mutex_unlock(&lock);
printf("consumer:%d\n",data);
sleep(100);
}
}
static void* producter(void* _h)
{
_node_p head=(_node_p) _h;
for(;;)
{
pthread_mutex_lock(&lock);
int i=rand()%1000;
push_List(head,i);
pthread_mutex_unlock(&lock);
printf("producter:%d\n",i);
pthread_cond_signal(&cond);
sleep(1);
}
}
結果圖: