多線程同步主要有信號(hào)量、互斥量、條件變量和讀寫鎖四種方式。
0. 背景
競(jìng)爭(zhēng)
#include <stdio.h>
#include <pthread.h>
void* func(void* arg){
printf("enter func\n");
sleep(1);
printf("do something\n");
sleep(1);
printf("level func\n");
}
int main(int argc,int argv[]){
pthread_t tids[3];
int i;
for(i=0;i<3;i++){
pthread_create(&tids[i],NULL,func,&mutex);
}
for(i=0;i<3;i++){
pthread_join(tids[i],NULL);
}
}
1. 信號(hào)量
1.1 操作
| No. |
操作 |
函數(shù) |
| 1 |
創(chuàng)建 |
int sem_init(sem_t *sem, int pshared, unsigned int value) |
| 2 |
銷毀 |
int sem_destroy(sem_t *sem) |
| 3 |
阻塞等待 |
int sem_wait(sem_t *sem) |
| 4 |
非阻塞等待 |
int sem_trywait(sem_t * sem) |
| 5 |
觸發(fā) |
int sem_post(sem_t *sem) |
1.1.1 創(chuàng)建
int sem_init(sem_t *sem, int pshared, unsigned int value)
| No. |
參數(shù) |
含義 |
| 1 |
sem |
信號(hào)量對(duì)象 |
| 2 |
pshared |
信號(hào)量類型。0:線程共享;<0:進(jìn)程共享 |
| 3 |
value |
初始值 |
| No. |
返回值 |
含義 |
| 1 |
0 |
成功 |
| 1 |
-1 |
失敗 |
1.1.2 銷毀
int sem_destroy(sem_t *sem)
| No. |
參數(shù) |
含義 |
| 1 |
sem |
信號(hào)量對(duì)象 |
| No. |
返回值 |
含義 |
| 1 |
0 |
成功 |
| 2 |
-1 |
失敗 |
1.2 等待
1.2.1 阻塞等待
int sem_wait(sem_t *sem)
| No. |
參數(shù) |
含義 |
| 1 |
sem |
信號(hào)量對(duì)象 |
| No. |
返回值 |
含義 |
| 1 |
0 |
成功 |
| 2 |
-1 |
失敗 |
1.2.2 非阻塞等待
int sem_trywait(sem_t * sem)
| No. |
參數(shù) |
含義 |
| 1 |
sem |
信號(hào)量對(duì)象 |
| No. |
返回值 |
含義 |
| 1 |
0 |
成功 |
| 2 |
-1 |
失敗 |
1.3 觸發(fā)
int sem_post(sem_t *sem)
| No. |
參數(shù) |
含義 |
| 1 |
sem |
信號(hào)量對(duì)象 |
| No. |
返回值 |
含義 |
| 1 |
0 |
成功 |
| 2 |
-1 |
失敗 |
#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
void* func(void* arg){
sem_wait(arg);
printf("enter func\n");
sleep(1);
printf("do something\n");
sleep(1);
printf("level func\n");
sem_post(arg);
}
int main(int argc,int argv[]){
sem_t sem;
sem_init(&sem,0,1);
pthread_t tids[3];
int i;
for(i=0;i<3;i++){
pthread_create(&tids[i],NULL,func,&sem);
}
for(i=0;i<3;i++){
pthread_join(tids[i],NULL);
}
sem_destroy(&sem);
}
2. 互斥量
2.1 分類
| No. |
分類 |
實(shí)現(xiàn) |
特點(diǎn) |
| 1 |
靜態(tài)分配互斥量 |
pthread_mutex_t mutex= PTHREAD_MUTEX_INITIALIZER; |
簡(jiǎn)單 |
| 2 |
動(dòng)態(tài)分配互斥量 |
pthread_mutex_init(&mutex, NULL);pthread_mutex_destroy(&mutex); |
可以設(shè)置更多的選項(xiàng) |
2.2 操作
| No. |
操作 |
函數(shù) |
| 1 |
加鎖 |
int pthread_mutex_lock(pthread_t *mutex) |
| 2 |
嘗試加鎖 |
int pthread_mutex_trylock(pthread_t *mutex) |
| 3 |
解鎖 |
int pthread_mutex_unlock(pthread_t *mutex) |
| No. |
參數(shù) |
含義 |
| 1 |
mutex |
互斥鎖 |
2.3 示例
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex= PTHREAD_MUTEX_INITIALIZER;
void* func(void* arg){
pthread_mutex_lock(&mutex);
printf("%ld enter func\n",pthread_self());
sleep(1);
printf("%ld do something\n",pthread_self());
sleep(1);
printf("%ld level func\n",pthread_self());
pthread_mutex_unlock(&mutex);
}
int main(int argc,int argv[]){
pthread_t tids[3];
int i;
for(i=0;i<3;i++){
pthread_create(&tids[i],NULL,func,NULL);
}
for(i=0;i<3;i++){
pthread_join(tids[i],NULL);
}
}
#include <stdio.h>
#include <pthread.h>
void* func(void* arg){
pthread_mutex_lock(arg);
printf("%ld enter func\n",pthread_self());
sleep(1);
printf("%ld do something\n",pthread_self());
sleep(1);
printf("%ld level func\n",pthread_self());
pthread_mutex_unlock(arg);
}
int main(int argc,int argv[]){
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL);
pthread_t tids[3];
int i;
for(i=0;i<3;i++){
pthread_create(&tids[i],NULL,func,&mutex);
}
for(i=0;i<3;i++){
pthread_join(tids[i],NULL);
}
pthread_mutex_destroy(&mutex);
}
2.4 可能出現(xiàn)的問(wèn)題
- 線程在解鎖之前退出。
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex= PTHREAD_MUTEX_INITIALIZER;
void* func(void* arg){
pthread_mutex_lock(&mutex);
printf("%ld enter func\n",pthread_self());
sleep(1);
printf("%ld do something\n",pthread_self());
pthread_exit(0);// 提前退出
sleep(1);
printf("%ld level func\n",pthread_self());
pthread_mutex_unlock(&mutex);
}
int main(int argc,int argv[]){
pthread_t tids[3];
int i;
for(i=0;i<3;i++){
pthread_create(&tids[i],NULL,func,NULL);
}
for(i=0;i<3;i++){
pthread_join(tids[i],NULL);
}
}
- 線程在解鎖之前被其他線程殺掉。
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex= PTHREAD_MUTEX_INITIALIZER;
void* func(void* arg){
pthread_mutex_lock(&mutex);
printf("%ld enter func\n",pthread_self());
sleep(1);
printf("%ld do something\n",pthread_self());
sleep(1);
printf("%ld level func\n",pthread_self());
pthread_mutex_unlock(&mutex);
}
void* hacker(void* arg){
sleep(1);
pthread_t* tids = arg;
pthread_cancel(tids[0]);
printf("Kill TID:%ld\n",tids[0]);
}
int main(int argc,int argv[]){
void* (*funcs[])(void*) = {func,func,func,hacker};
pthread_t tids[4];
int i;
for(i=0;i<4;i++){
pthread_create(&tids[i],NULL,funcs[i],tids);
}
for(i=0;i<4;i++){
pthread_join(tids[i],NULL);
}
}
- 更加安全的做法
使用pthread_cleanup,保證線程正?;蛘弋惓M顺龆寄茚尫呕コ怄i。
線程在解鎖之前退出解決方式
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex= PTHREAD_MUTEX_INITIALIZER;
void* func(void* arg){
pthread_cleanup_push(pthread_mutex_unlock,&mutex);
pthread_mutex_lock(&mutex);
printf("%ld enter func\n",pthread_self());
sleep(1);
printf("%ld do something\n",pthread_self());
pthread_exit(0);// 提前退出
sleep(1);
printf("%ld level func\n",pthread_self());
pthread_mutex_unlock(&mutex);
pthread_cleanup_pop(0);
}
int main(int argc,int argv[]){
pthread_t tids[3];
int i;
for(i=0;i<3;i++){
pthread_create(&tids[i],NULL,func,NULL);
}
for(i=0;i<3;i++){
pthread_join(tids[i],NULL);
}
}
線程在解鎖之前被其他線程殺掉解決方式
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex= PTHREAD_MUTEX_INITIALIZER;
void* func(void* arg){
pthread_cleanup_push(pthread_mutex_unlock,&mutex);
pthread_mutex_lock(&mutex);
printf("%ld enter func\n",pthread_self());
sleep(1);
printf("%ld do something\n",pthread_self());
sleep(1);
printf("%ld level func\n",pthread_self());
pthread_exit(0);
pthread_cleanup_pop(0);
}
void* hacker(void* arg){
sleep(1);
pthread_t* tids = arg;
pthread_cancel(tids[0]);
printf("Kill TID:%ld\n",tids[0]);
}
int main(int argc,int argv[]){
void* (*funcs[])(void*) = {func,func,func,hacker};
pthread_t tids[4];
int i;
for(i=0;i<4;i++){
pthread_create(&tids[i],NULL,funcs[i],tids);
}
for(i=0;i<4;i++){
pthread_join(tids[i],NULL);
}
}
動(dòng)態(tài)分配互斥量使用方式,也使用pthread_cleanup
#include <stdio.h>
#include <pthread.h>
void* func(void* arg){
pthread_cleanup_push(pthread_mutex_unlock,arg);
pthread_mutex_lock(arg);
printf("%ld enter func\n",pthread_self());
sleep(1);
printf("%ld do something\n",pthread_self());
sleep(1);
printf("%ld level func\n",pthread_self());
pthread_exit(0); // 退出才能出發(fā)clean_up
pthread_cleanup_pop(0);
}
int main(int argc,int argv[]){
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL);
pthread_t tids[3];
int i;
for(i=0;i<3;i++){
pthread_create(&tids[i],NULL,func,&mutex);
}
for(i=0;i<3;i++){
pthread_join(tids[i],NULL);
}
pthread_mutex_destroy(&mutex);
}
2.5 基本套路
在線程處理函數(shù)中使用互斥量的基本套路
pthread_cleanup_push(pthread_mutex_unlock,pmutex);
pthread_mutex_lock(pmutex);
// do something
pthread_exit(0); // 退出才能出發(fā)clean_up
pthread_cleanup_pop(0);
2.6 信號(hào)量與互斥量的區(qū)別
| No. |
區(qū)別 |
信號(hào)量 |
互斥量 |
| 1 |
使用對(duì)象 |
線程和進(jìn)程 |
線程 |
| 2 |
量值 |
非負(fù)整數(shù) |
0或1 |
| 3 |
操作 |
PV操作可由不同線程完成 |
加鎖和解鎖必須由同一線程使用 |
| 4 |
應(yīng)用 |
用于線程的同步 |
用于線程的互斥 |
- 互斥:主要關(guān)注于資源訪問(wèn)的唯一性和排他性。
- 同步:主要關(guān)注于操作的順序,同步以互斥為前提。
3 條件變量
- 概念
線程掛起直到共享數(shù)據(jù)的某些條件得到滿足
3.1 分類
| No. |
分類 |
實(shí)現(xiàn) |
特點(diǎn) |
| 1 |
靜態(tài)分配條件變量 |
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; |
簡(jiǎn)單 |
| 2 |
動(dòng)態(tài)分配靜態(tài)變量 |
pthread_cond_init(&cond, NULL);pthread_cond_destroy(&cond); |
可以設(shè)置更多的選項(xiàng) |
3.2 操作
| No. |
操作 |
函數(shù) |
| 1 |
條件等待 |
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) |
| 2 |
計(jì)時(shí)等待 |
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) |
| 3 |
單個(gè)激活 |
int pthread_cond_signal(pthread_cond_t *cond) |
| 4 |
全部激活 |
int pthread_cond_broadcast(pthread_cond_t *cond) |
3.2.1 等待
3.2.1.1 條件等待
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
| No. |
參數(shù) |
含義 |
| 1 |
cond |
條件變量 |
| 2 |
mutex |
互斥鎖 |
3.2.1.2 計(jì)時(shí)等待
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
| No. |
參數(shù) |
含義 |
| 1 |
cond |
條件變量 |
| 2 |
mutex |
互斥鎖 |
| 3 |
abstime |
等待時(shí)間 |
| No. |
返回值 |
含義 |
| 1 |
ETIMEDOUT |
超時(shí)結(jié)束等待 |
3.2.2 激活
3.2.2.1 單個(gè)激活
int pthread_cond_signal(pthread_cond_t *cond)
| No. |
參數(shù) |
含義 |
| 1 |
cond |
條件變量 |
| No. |
返回值 |
含義 |
| 1 |
0 |
成功 |
| 2 |
正數(shù) |
錯(cuò)誤碼 |
3.2.2.2 全部激活
int pthread_cond_broadcast(pthread_cond_t *cond)
| No. |
參數(shù) |
含義 |
| 1 |
cond |
條件變量 |
| No. |
返回值 |
含義 |
| 1 |
0 |
成功 |
| 2 |
正數(shù) |
錯(cuò)誤碼 |
套路
條件變量一般與互斥鎖一起使用。
pthread_mutex_lock(&mutex);
// do something
if(判斷條件){
pthread_cond_signal(&cond);// 喚醒單個(gè)
// 或者
pthread_cond_broadcast(&cond);// 喚醒多個(gè)
}
pthread_mutex_unlock(&mutex);
pthread_mutex_lock(&mutex);
while(判斷條件){
pthread_cond_wait(&cond,&mutex);
}
// do something
// 把判斷條件改為false
pthread_mutex_unlock(&mutex);
流程分析
- 主線程:等待子線程發(fā)信號(hào)。
- 子線程:每隔3秒計(jì)數(shù)一次,當(dāng)數(shù)字是3的倍數(shù)時(shí)通知主進(jìn)程。
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdbool.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
bool condition = false;
#define LOG(msg) printf("%s:%s\n",__func__ ,msg);
void* ChildFunc(void* arg){
int i = 0;
while(true){
LOG("Enter");
pthread_mutex_lock(&mutex);
LOG("Get Lock");
printf("%d\n",++i);
if(0 == i%3){
condition = true;
LOG("Begin Send Single");
pthread_cond_signal(&cond);// 喚醒單個(gè)
LOG("End Send Single");
}
sleep(3);
pthread_mutex_unlock(&mutex);
LOG("Lose Lock");
LOG("Leave");
}
}
void MainFunc(){
while(true){
LOG("Enter");
pthread_mutex_lock(&mutex);
LOG("Get Lock");
while(!condition){
LOG("Begin Wait Single");
pthread_cond_wait(&cond,&mutex);
LOG("End Wait Single");
}
condition = false;
pthread_mutex_unlock(&mutex);
LOG("Lose Lock");
LOG("Leave");
}
}
int main(){
pthread_t tid;
pthread_create(&tid,NULL,ChildFunc,NULL);
MainFunc();
pthread_join(tid,NULL);
return 0;
}
問(wèn)題:
- 主線程在
pthread_cond_wait()時(shí),是否釋放互斥鎖?
- 主線程在什么時(shí)候重新獲得互斥鎖?
案例
模擬放票和搶票:實(shí)現(xiàn)生產(chǎn)者消費(fèi)者問(wèn)題
#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int num = 0;
void* GetTicket(void*){
while(true){
// 記錄資源釋放操作
pthread_cleanup_push((void (*)(void*))pthread_mutex_unlock,&mutex);
pthread_mutex_lock(&mutex);
if(0<num){ // 二次檢查
--num;
cout << pthread_self() << "取走1張票,還剩" << num << "張票" << endl;
}else{
cout << pthread_self() << " exit" << endl;
pthread_exit(0);// 只能使用pthread_exit()
}
pthread_mutex_unlock(&mutex);
usleep(100000); // 模擬耗時(shí)操作
pthread_cleanup_pop(0);// 調(diào)用pthread_exit()后線程退出自動(dòng)釋放資源
}
}
int main(){
num = 100; // 必須提前存入車票
pthread_t tids[5];
for(int i=0;i<5;++i){
pthread_create(tids+i,NULL,GetTicket,NULL);
}
// 主線程放票
for(int i = 0;i<5;++i){
pthread_mutex_lock(&mutex);
num += 40;
cout << "主線程放票"<<num<<"張,現(xiàn)存" << num <<"票" << endl;
pthread_mutex_unlock(&mutex);
usleep(100000); // 模擬耗時(shí)操作
}
for(int i=0;i<5;++i){
pthread_join(tids[i],NULL);
}
}
- 使用條件變量實(shí)現(xiàn)
使用互斥量實(shí)現(xiàn)的存在兩個(gè)缺點(diǎn)
- 初始票數(shù)不能為0,否則搶票線程剛開始回退出。
- 搶票過(guò)程票數(shù)不能為0,否則搶票線程剛開始回退出。
可以使用條件變量使搶票線程在票數(shù)為0時(shí)阻塞等待。
#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;
struct Data{
pthread_mutex_t* pmutex;
pthread_cond_t* pcond;
int* pnum;
int* pcount;
};
void* GetTicket(void* arg){
Data* pdata = (Data*)arg;
while(true){
// 記錄資源釋放操作
pthread_cleanup_push((void (*)(void*))pthread_mutex_unlock,pdata->pmutex);
pthread_mutex_lock(pdata->pmutex);
while(0>=*(pdata->pnum)){
if(0==*(pdata->pnum) && 0==(*pdata->pcount)){
cout << pthread_self() << " exit" << endl;
pthread_exit(0);// 只能使用pthread_exit()
}
pthread_cond_wait(pdata->pcond,pdata->pmutex);// 1.條件不滿足阻塞,并且自動(dòng)釋放互斥鎖
// 2.等待board_castt信號(hào),重新?lián)寠Z互斥鎖
}
--*(pdata->pnum);
cout << pthread_self() << "取走1張票,還剩" << *(pdata->pnum) << "張票" << endl;
pthread_mutex_unlock(pdata->pmutex);
usleep(100000); // 模擬耗時(shí)操作
pthread_cleanup_pop(0);// 調(diào)用pthread_exit()后線程退出自動(dòng)釋放資源
}
}
int main(){
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL);
pthread_cond_t cond;
pthread_cond_init(&cond,NULL);
int num = 0;
int count = 5;
pthread_t tids[5];
Data data = {&mutex,&cond,&num,&count};
for(int i=0;i<5;++i){
pthread_create(tids+i,NULL,GetTicket,&data);
}
// 主線程放票
while(count--){
pthread_mutex_lock(&mutex);
num += 20;
cout << "主線程放票" << num << "張,現(xiàn)存" << num <<"票" << endl;
pthread_mutex_unlock(&mutex);
pthread_cond_broadcast(&cond);// 喚醒所有在wait線程
sleep(1); // 模擬耗時(shí)操作
}
for(int i=0;i<5;++i){
pthread_join(tids[i],NULL);
}
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
}
老板與會(huì)計(jì)的約定:每筆超過(guò)1000元的支出必須老板批準(zhǔn)同意,低于1000元的會(huì)計(jì)可以自行決定。
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int currency = 0 ;
int signal_cnt = 0;
void* checkout(void* arg){
sleep(1);
for(;;){
pthread_mutex_lock(&mutex);
printf("checkout enter\n");
currency = rand()%2000;
printf("spend %d\n",currency);
if(currency >= 1000){
printf("\033[42;31msignal boss:%d\033[0m\n");
pthread_cond_signal(&cond);
signal_cnt++;
}
printf("checkout leave\n");
pthread_mutex_unlock(&mutex);
//sched_yield();
sleep(1);
}
}
void* boss(void* arg){
for(;;){
pthread_mutex_lock(&mutex);
printf("boss enter\n");
while(currency < 1000){
printf("boss wait\n");
pthread_cond_wait(&cond,&mutex);
}
signal_cnt--;
printf("\033[46;31mboss agress:%d signal_cnt:%d\033[0m\n",currency,signal_cnt);
currency = 0;
printf("boss leave\n");
pthread_mutex_unlock(&mutex);
}
}
int main(){
typedef void*(*func_t)(void*);
func_t funcs[2] = {boss,checkout};
pthread_t tids[2];
int i;
pthread_setconcurrency(2);
for(i=0;i<2;i++){
pthread_create(&tids[i],NULL,funcs[i],tids);
}
for(i=0;i<2;i++){
pthread_join(tids[i],NULL);
}
}
問(wèn)題
4. 讀寫鎖
資源訪問(wèn)分為兩種情況:讀操作和寫操作。
讀寫鎖比mutex有更高的適用性,可以多個(gè)線程同時(shí)占用讀模式的讀寫鎖,但是只能一個(gè)線程占用寫模式的讀寫鎖。
- 當(dāng)讀寫鎖是寫加鎖狀態(tài)時(shí),在這個(gè)鎖被解鎖之前,所有試圖對(duì)這個(gè)鎖加鎖的線程都會(huì)被阻塞;
- 當(dāng)讀寫鎖在讀加鎖狀態(tài)時(shí),所有試圖以讀模式對(duì)它進(jìn)行加鎖的線程都可以得到訪問(wèn)權(quán),但是以寫模式對(duì)它進(jìn)行枷鎖的線程將阻塞;
- 當(dāng)讀寫鎖在讀模式鎖狀態(tài)時(shí),如果有另外線程試圖以寫模式加鎖,讀寫鎖通常會(huì)阻塞隨后的讀模式鎖請(qǐng)求,這樣可以避免讀模式鎖長(zhǎng)期占用,而等待的寫模式鎖請(qǐng)求長(zhǎng)期阻塞;
這種鎖適用對(duì)數(shù)據(jù)結(jié)構(gòu)進(jìn)行讀的次數(shù)比寫的次數(shù)多的情況下,因?yàn)榭梢赃M(jìn)行讀鎖共享。
新聞發(fā)布會(huì)
領(lǐng)導(dǎo)發(fā)言與聊天
- 概念
共享獨(dú)占
讀取鎖(共享)
寫入鎖(獨(dú)占)
4.1 分類
| No. |
分類 |
實(shí)現(xiàn) |
特點(diǎn) |
| 1 |
靜態(tài)分配讀寫鎖 |
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER |
簡(jiǎn)單 |
| 2 |
動(dòng)態(tài)分配讀寫鎖 |
pthread_rwlock_init(&rwlock, NULL);pthread_rwlock_destroy(&rwlock); |
可以設(shè)置更多的選項(xiàng) |
4.2 操作
4.2.1 加鎖
4.2.1.1 讀取鎖
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
4.2.1.2 寫入鎖
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
4.2.2 解鎖
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
火車票的查詢與購(gòu)買
#include <stdio.h>
#include <pthread.h>
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
int count = 10000;
int put_cur = 0;
void* search(void* arg){
for(;;){
pthread_rwlock_rdlock(&rwlock);
printf("leave %d\n",count);
usleep(500000);
pthread_rwlock_unlock(&rwlock);
}
}
void rollback(void* arg){
count -= put_cur;
printf("rollback %d to %d\n",put_cur,count);
pthread_rwlock_unlock(&rwlock);
}
void* put(void* arg){
pthread_cleanup_push(rollback,NULL);
for(;;){
pthread_rwlock_wrlock(&rwlock);
put_cur = rand()%1000;
count += put_cur;
printf("put %d ok,leave %d\n",put_cur,count);
usleep(500000);
pthread_rwlock_unlock(&rwlock);
}
pthread_cleanup_pop(0);
}
void* hacker(void* arg){
sleep(2);
pthread_t* ptids = arg;
pthread_cancel(ptids[0]);
printf("\033[41;34mcancel %lu\033[0m\n",ptids[0]);
}
void* get(void* arg){
for(;;){
pthread_rwlock_wrlock(&rwlock);
int cur = rand()%1000;
if(count>cur){
count -= cur;
printf("crash %d leave %d\n",cur,count);
}else{
printf("leave not enought %d\n",count);
}
usleep(500000);
pthread_rwlock_unlock(&rwlock);
}
}
int main(){
pthread_t tids[4];
typedef void*(*func_t)(void*);
func_t funcs[4] = {put,get,search,hacker};
int i=0;
pthread_setconcurrency(4);
for(i=0;i<4;i++){
pthread_create(&tids[i],NULL,funcs[i],tids);
}
for(i=0;i<4;i++){
pthread_join(tids[i],NULL);
}
}
四個(gè)線程:一個(gè)查看、一個(gè)放票、一個(gè)取票、一個(gè)隨機(jī)破壞。