Linux系統(tǒng)編程9:多線程同步

多線程同步主要有信號(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 失敗
  • 示例
    解決競(jìng)爭(zhēng)
#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. 互斥量

  • 比喻
    ATM取款
    toilet

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)
  • 參數(shù)
No. 參數(shù) 含義
1 mutex 互斥鎖

2.3 示例

  • 靜態(tài)分配互斥量使用方式
#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);
    }
}
  • 動(dòng)態(tài)分配互斥量使用方式
#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)題

  1. 線程在解鎖之前退出。
#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);
    }
}
  1. 線程在解鎖之前被其他線程殺掉。
#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ò)誤碼

套路

條件變量一般與互斥鎖一起使用。

  • 條件變量發(fā)送信號(hào)
pthread_mutex_lock(&mutex);
 
// do something
if(判斷條件){
    pthread_cond_signal(&cond);// 喚醒單個(gè)
    // 或者
    pthread_cond_broadcast(&cond);// 喚醒多個(gè)
}
 
pthread_mutex_unlock(&mutex);
  • 條件變量等待信號(hào)
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)題

  • 使用互斥量實(shí)現(xià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)
  1. 初始票數(shù)不能為0,否則搶票線程剛開始回退出。
  2. 搶票過(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è)線程占用寫模式的讀寫鎖。

  1. 當(dāng)讀寫鎖是寫加鎖狀態(tài)時(shí),在這個(gè)鎖被解鎖之前,所有試圖對(duì)這個(gè)鎖加鎖的線程都會(huì)被阻塞;
  2. 當(dāng)讀寫鎖在讀加鎖狀態(tài)時(shí),所有試圖以讀模式對(duì)它進(jìn)行加鎖的線程都可以得到訪問(wèn)權(quán),但是以寫模式對(duì)它進(jìn)行枷鎖的線程將阻塞;
  3. 當(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ī)破壞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 第三章 Java內(nèi)存模型 3.1 Java內(nèi)存模型的基礎(chǔ) 通信在共享內(nèi)存的模型里,通過(guò)寫-讀內(nèi)存中的公共狀態(tài)進(jìn)行隱...
    澤毛閱讀 4,502評(píng)論 2 21
  • 線程池ThreadPoolExecutor corepoolsize:核心池的大小,默認(rèn)情況下,在創(chuàng)建了線程池之后...
    irckwk1閱讀 864評(píng)論 0 0
  • 一段情感里兩個(gè)人走向婚姻的殿堂是否預(yù)示著緣分已落地生根?還是一起攜手從韶華到白發(fā)才算是?似乎關(guān)于愛情的話題永遠(yuǎn)都...
    艾特我和你閱讀 459評(píng)論 0 1
  • 一年有四季,所以四個(gè)季節(jié)的太陽(yáng)是不一樣的。 我畫了個(gè)彩色的太陽(yáng),掛在春天的天空,春回大地,萬(wàn)物復(fù)蘇...
    小王子WXN閱讀 311評(píng)論 0 1
  • 我是兩個(gè)孩的孩媽,忙并快樂(lè)著,一直以來(lái)都想寫一些自己的感悟與大家分享,今天無(wú)意中與《簡(jiǎn)書》有緣,希望在以后的交...
    知足常樂(lè)_a6bd閱讀 170評(píng)論 0 0

友情鏈接更多精彩內(nèi)容