鎖的注意事項
1、盡量保證鎖的粒度,越小越好。(訪問共享數據前,加鎖,訪問結束后立即解鎖)
2、互斥鎖,本質是結構體,但是可以看成整數,初值為1。(pthread_mutex_init調用成功)
3、加鎖: --操作,阻塞線程
4、解鎖:++操作,喚醒阻塞在鎖上的進程
try鎖:嘗試加鎖 , 成功-- , 失敗:返回錯誤號(EBUSY),不阻塞。
讀寫鎖(三句話)
讀寫鎖只有一把,但是具備兩種狀態。
“寫模式加鎖”:解鎖前,所有對該鎖加鎖的線程都會被阻塞。
“讀模式加鎖”:其他線程用讀模式加鎖會成功,寫模式加鎖則阻塞。
“讀模式加鎖”:既有試圖寫模式加鎖的線程也有讀模式加鎖的線程,那么讀寫鎖會阻塞隨后的讀模式鎖請求,優先滿足寫模式鎖,讀寫鎖并行阻塞,寫鎖優先級高。
寫獨占、讀共享。
相較于互斥量而言,當讀線程多的時候,提高訪問效率。鎖一般都定義成全局變量。
主要應用函數pthread_rwlock_xxx
pthread_rwlock_t rwlock; 創建讀寫鎖pthread_rwlock_init
pthread_rwlock_destroy
pthread_rwlock_rdlock
pthread_rwlock_wrlock
pthread_rwlock_tryrdlock
pthread_rwlock_trywrlock
pthread_rwlock_unlock成功返回0,失敗返回錯誤號
?3個線程不定時寫同一全局資源 , 5個線程不定時讀同一全局資源.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>pthread_rwlock_t rwlock;
int counter = 20;void* th_write(void* arg){int t;int ret;int i = (int)arg;while(1){ret = pthread_rwlock_wrlock(&rwlock);if(ret != 0){fprintf(stderr , "pthread_rwlock_wrlock error with :%s\n" , strerror(ret));exit(1);}t = counter;usleep(1000);printf("-----write %d: %lu: counter=%d , counter++ = %d\n" , i , pthread_self() , t , ++counter);ret = pthread_rwlock_unlock(&rwlock);if(ret != 0){fprintf(stderr , "pthread_rwlock_unlock error with :%s\n" , strerror(ret));exit(1);}usleep(10000);}return NULL;
}void* th_read(void* arg){int i = (int)arg;int ret;while(1){ret = pthread_rwlock_rdlock(&rwlock);if(ret != 0){fprintf(stderr , "pthread_rwlock_rdlock error with :%s\n" , strerror(ret));exit(1);}printf("-------read %d: %lu: counter = %d\n", i , pthread_self() , counter);ret = pthread_rwlock_unlock(&rwlock);if(ret != 0){fprintf(stderr , "pthread_rwlock_unlock error with :%s\n" , strerror(ret));exit(1);}usleep(2000);}return NULL;
}int main(int argc , char *argv[])
{pthread_t tid[8];int ret ;int i ;ret = pthread_rwlock_init(&rwlock , NULL);if(ret != 0){fprintf(stderr , "pthread_rwlock_init error with :%s\n" , strerror(ret));exit(1);}for(i =0 ; i < 3 ; i++ ){ret = pthread_create(&tid[i], NULL , th_write ,(void*)i);if(ret != 0){fprintf(stderr , "pthread_create error with :%s\n" , strerror(ret));exit(1);}}for(i = 0 ; i < 5 ; i++){ret = pthread_create(&tid[i+3] , NULL , th_read , (void*)i);if(ret != 0){fprintf(stderr , "pthread_create error with :%s\n" , strerror(ret));exit(1);}}for(i = 0 ; i < 8 ; i++){pthread_join(&tid[i] , NULL);if(ret != 0){fprintf(stderr , "pthread_join error with :%s\n" , strerror(ret));exit(1);}}pthread_rwlock_destroy(&rwlock);return 0 ;
}
死鎖
使用鎖不恰當導致的現象。條件
1、線程試圖對同一個互斥量加鎖兩次
2、線程1擁有A鎖 , 請求獲得B鎖 , 線程2擁有B鎖,請求獲得A鎖。
條件變量
本身不是鎖,但是通常要結合鎖來使用。(等待某一個變量滿足)。
pthread_cond_t cond; 創建讀寫鎖pthread_cond_init
pthread_cond_destroy
pthread_cond_wait
pthread_cond_timewait
pthread_cond_signal
pthread_cond_broadcast成功返回0,失敗返回錯誤號
pthread_cond_wait函數
阻塞等待一個條件變量
int pthread_cond_wait(&cond , pthread_mutex_t *restrict murex);
函數作用:
1、阻塞等待條件變量cond滿足。
2、釋放已掌握的互斥鎖(解鎖),相當于pthread_mutex_unlock(&mutex);? ?1,2兩步為一個原子操作。
3、當被喚醒,pthread_cond_wait函數返回時,解除阻塞并重新申請獲取互斥鎖Pthread_mutex_lock(&mutex).
?生產者、消費者模型
pthread_cond_signal函數
喚醒阻塞在條件變量上的一個線程
pthread_cond_broadcast函數
喚醒阻塞在條件變量上的多個線程
要求借助條件變量完成生產者消費者模型
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>struct msg{int num;struct msg* next;
};pthread_mutex_t mutex;
pthread_cond_t has_data = PTHREAD_COND_INITIALIZER;struct msg * head;void err_thread(int ret , char*str)
{if(ret != 0){fprintf(stderr , "%s:%s\n" ,str , strerror(ret));pthread_exit(NULL);}
}void* produser(void* arg)
{int ret ;while(1){struct msg *mp;mp = malloc(sizeof(struct msg));mp->num = rand() % 1000 + 1;pthread_mutex_lock(&mutex);if(ret != 0)err_thread(ret , "pthread_mutex_lock error");head = mp;printf("------prod:%d , pid:%lu\n" , mp->num , pthread_self());pthread_mutex_unlock(&mutex);if(ret != 0)err_thread(ret , "pthread_mutex_unlock error");ret = pthread_cond_signal(&has_data);if(ret != 0)err_thread(ret , "pthread_mutex_lock error");sleep(rand() % 3);}return NULL;
}void* consumer(void* arg)
{int ret;while(1){struct msg *mp;mp = head;ret = pthread_mutex_lock(&mutex);if(ret != 0)err_thread(ret , "pthread_mutex_lock error");while(head == NULL){ret = pthread_cond_wait(&has_data , &mutex); // pthread_cond_wait函數返回時,重新加鎖mutex。if(ret != 0 )err_thread(ret , "pthread_con_wait error");}mp = head;head = mp->next;ret = pthread_mutex_unlock(&mutex);if(ret != 0)err_thread(ret , "pthread_mutex_lock error");printf("-------cons:%d , cid:%lu\n" , mp->num , pthread_self());sleep(rand()%3);free(mp);}return NULL;
}int main(int argc , char *argv[])
{pthread_t pid , cid;srand(time(NULL));int ret;ret = pthread_mutex_init(&mutex , NULL);if(ret != 0)err_thread(ret , "pthread_create error");ret = pthread_create(&pid , NULL , produser , NULL);if(ret != 0)err_thread(ret , "pthread_create error");ret = pthread_create(&cid , NULL , consumer , NULL);if(ret != 0)err_thread(ret , "pthread_create error");pthread_join(pid , NULL);pthread_join(cid , NULL);return 0 ;
}
信號量
應用于線程、進程間同步。
相當于初始化值為 N?的互斥量。 N 為可同時訪問的進程數。
sem_init()
sem_destroy()
sem_wait() //相當于加鎖
sem_trywait()
sem_timewait()
sem_post() //相當于解鎖返回值:成功返回0 , 失敗返回errno
sem_wait 信號量>0,信號量-- ;信號量 = 0 ,線程阻塞。? 對比pthread_mutex_lock()。?
sem_post 信號量++, 喚醒阻塞在信號量上的線程
信號量的初值,決定了占用信號量的線程個數。
?sem_init()函數
int sem_init(sem_t *sem , int pshared , unsigned int value);pshared: 0:用于線程間同步1:用于進程間同步value :N值 (指定同時訪問的數目)
信號量的生產者消費者模型
?
主要是明白wait和post的關系,以及阻塞在哪的關系。?
重點:
sem_wait 信號量>0,信號量-- ;信號量 = 0 ,線程阻塞。? 對比pthread_mutex_lock()。?
sem_post 信號量++, 喚醒阻塞在信號量上的線程
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
#define NUM 5
int queue[NUM];
sem_t blank_number;
sem_t stat_number;void err_thread(int ret , char*str)
{if(ret != 0 ){fprintf(stderr , "%s:%s\n" , str , strerror(ret));pthread_exit(NULL);}
}void* produser(void* arg)
{int i = 0;while(1){sem_wait(&blank_number);//空格子數--queue[i] = rand()%1000 + 1;printf("---produce:%d\n" , queue[i]);sem_post(&stat_number); // 產品數++i = (i+1) % NUM; // 借助隊列下標實現環形隊列sleep(rand()%1);}return NULL;
}void* consumer(void* arg)
{int i = 0;while(1){sem_wait(&stat_number);printf("-----consume:%d\n" , queue[i]);queue[i] = 0;sem_post(&blank_number);i = (i + 1)% NUM;sleep(rand()%3);}return NULL;
}int main(int argc , char *argv[])
{pthread_t pid , cid;int ret ;srand(time(NULL));sem_init(&blank_number , 0 , NUM);sem_init(&stat_number , 0 , 0);ret = pthread_create(&pid , NULL , produser , NULL);if(ret != 0)err_thread(ret , "pthread_create error");ret = pthread_create(&cid , NULL , consumer , NULL);if(ret != 0)err_thread(ret , "pthread_create error");pthread_join(pid , NULL);pthread_join(cid , NULL);sem_destroy(&blank_number);sem_destroy(&stat_number);return 0 ;
}
系統編程完結撒花!開始網絡編程咯~