线程的同步与互斥
1. 互斥量
????在Linux 下線程使用的都是局部變量, 而我們知道, 每一個(gè)線程都獨(dú)立擁有自己的一個(gè)棧, 而這些局部便令就在棧中,而線程的創(chuàng)建就是為了實(shí)現(xiàn)通信, 此時(shí)線程之間無(wú)法共享這些變量
????為了使得線程之間能夠共享數(shù)據(jù), 一次我們可以創(chuàng)建一個(gè)全局變量, 此時(shí)線程都在進(jìn)程內(nèi)部共享一個(gè)地址空間, 因此個(gè)線程之間就可以看到這個(gè)全局變量了
????但是問(wèn)題又來(lái)了, 創(chuàng)建了全局變量, 線程之間其實(shí)看到了一份公共資源, 而此時(shí)一個(gè)線程之間由于共同訪問(wèn)這個(gè)局部變量很有可能造成線程之間的不安全, 為了使得線程之間能夠正確訪問(wèn), 我們就引入了互斥量.我們規(guī)定,當(dāng)代碼進(jìn)入臨界區(qū)執(zhí)行的時(shí)候, 不允許其他線程進(jìn)入該臨界區(qū). 當(dāng)有多個(gè)線程要求執(zhí)行臨界區(qū)的代碼時(shí),此時(shí)如果臨界區(qū)沒(méi)有如何線程的時(shí)候, 操作系統(tǒng)只允許一個(gè)線程進(jìn)入該臨界區(qū), 而其他的線程則必須在臨界區(qū)外等待, 直到進(jìn)入臨界區(qū)的線程走出臨界區(qū), 并且釋放互斥量.如果線程不在臨界區(qū)內(nèi), 該線程不能組織其他線程進(jìn)入臨界區(qū)
2.互斥量相關(guān)接口
1.初始化互斥量 pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t* restict attr);參數(shù):mutex:要初始化的互斥量attr: NULL 2.銷(xiāo)毀互斥量 int pthread_mutex_destroy(pthread_mutex_t* mutex); 3.互斥量的加鎖 int pthread_mutex_lock(pthrea_mutex_t* mutex); 4.互斥量的解鎖 int pthread_mutex_unlock(pthread_mutex_t* mutex);????注意, 互斥量處于互斥狀態(tài)時(shí), 加鎖函數(shù)會(huì)將該互斥量鎖定, 同時(shí)返回成功, 當(dāng)發(fā)起加鎖函數(shù)被調(diào)用的時(shí)候, 其他線程已經(jīng)鎖定互斥量, 或者當(dāng)好多線程同時(shí)申請(qǐng)互斥量的時(shí)候, 此時(shí)線程之間就在相互競(jìng)爭(zhēng)這個(gè)互斥量,此時(shí), 該函數(shù)調(diào)用將會(huì)陷入阻塞狀態(tài),一直等待該互斥量, 直到擁有該互斥量的線程主動(dòng)釋放該互斥鎖
#include<stdio.h> #include<pthread.h> #include<string.h> #include<unistd.h> #include<stdlib.h>int ticket = 100; pthread_mutex_t mutex; void* route(void* arg) {char* id = (char*)arg;while(1){//pthread_mutex_lock(&mutex);if(ticket > 0){usleep(10000);printf("%s sells ticket:%d\n", id, ticket);ticket--;//pthread_mutex_unlock(&mutex);}else{//pthread_mutex_unlock(&mutex);break;}} } int main() {pthread_t t1, t2, t3, t4;pthread_mutex_init(&mutex, NULL);pthread_create(&t1, NULL, route, "thread 1");pthread_create(&t2, NULL, route, "thread 2");pthread_create(&t3, NULL, route, "thread 3");pthread_create(&t4, NULL, route, "thread 4");pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);return 0; }???????????????????????????????????
????由上圖可以看出, 由于我們未加互斥鎖, 線程對(duì)數(shù)據(jù)的不正確操作造成了數(shù)據(jù)的錯(cuò)誤,當(dāng)我我們?cè)诰€程進(jìn)入臨界區(qū)的時(shí)候臨界資源加上互斥鎖, 而在線程離開(kāi)臨界區(qū)的時(shí)候?qū)コ饬窟M(jìn)行釋放, 此時(shí)就不會(huì)出現(xiàn)數(shù)據(jù)錯(cuò)誤的現(xiàn)象了
???????????????????????????????????
3. 條件變量
????當(dāng)一個(gè)線程互斥訪問(wèn)某個(gè)變量時(shí), 它可能發(fā)現(xiàn)在其他線程改變狀態(tài)的之前它什么也不能做, 例如一個(gè)線程訪問(wèn)隊(duì)列時(shí), 它發(fā)現(xiàn)這個(gè)隊(duì)列為空, 此時(shí),它只能等待, 直到其他線程將結(jié)點(diǎn)放到該隊(duì)列.這時(shí), 為了使得各個(gè)線程之間能夠同步的訪問(wèn)這個(gè)變量,此時(shí)就需要有一個(gè)變量, 該變量必須要符合某個(gè)條件時(shí), 線程才能訪問(wèn)這個(gè)變量.
4. 相關(guān)接口
1. 初始化 int pthread_cond_init(pthread_cond_t* restrict cond, const pthread_condattr_t* restrict attr);cond: 表示要初始化的條件變量attr: NULL 2. 銷(xiāo)毀 int pthread_cond_destroy(pthread_cond_t* cond) 3. 等待條件滿足 int pthread_cond_wait(pthread_cond_t* restrict cond, pthread_mutex_t* restrict mutex);cond: 如果條件不滿足, 就在條件變量上等待mutex: 互斥量, 表名線程退出時(shí)必須釋放哪一個(gè)鎖 4. 喚醒 int pthread_cond_broadcast(pthread_cond_t* cond);用來(lái)喚醒一群線程 int pthread_cond_signal(pthread_cond_t* cond);用來(lái)喚醒某個(gè)線程????也許你會(huì)問(wèn), 既然線程等待, 那就直接等待就好了, 有一個(gè)條件變量就可以了, 但是為什么好要有一個(gè)互斥量呢?通過(guò)上面所述, 我們知道, 條件變量是為了使得線程之間得到同步所采用的一種手段. 當(dāng)只有一個(gè)線程的時(shí)候, 條件不滿足, 此時(shí)線程等待, 一直等待下去, 此時(shí)由于只有一個(gè)線程, 該線程所等待的條件將始終不會(huì)得到滿足, 一次線程將會(huì)一直等待下去. 所以, 為了能夠及時(shí)通知等待的線程, 必須有另外的線程對(duì)等待的這個(gè)條件(共享變量)做出預(yù)定的操作, 使得等待的線程所等待的條件得到滿足, 此時(shí), 這個(gè)條件變量是一個(gè)共享變量, 為了使得每一個(gè)線程訪問(wèn)該數(shù)據(jù)的正確性, 此時(shí)就必須引入互斥量來(lái)保證臨界資源的正確性.
#include<stdio.h> #include<unistd.h> #include<pthread.h> #include<stdlib.h> #include<string.h>pthread_cond_t cond; pthread_mutex_t mutex;void* thread1(void* arg) {while(1){printf("%s\n", (char*)arg);pthread_cond_wait(&cond, &mutex);printf("活動(dòng)\n");} }void* thread2(void* arg) {while(1){sleep(2);printf("%s\n", (char*)arg);pthread_cond_signal(&cond);} } int main() {pthread_t t1;pthread_t t2;pthread_cond_init(&cond, NULL);pthread_mutex_init(&mutex, NULL);pthread_create(&t1, NULL, thread1, "thread1");pthread_create(&t2, NULL, thread2, "thread2");pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_cond_destroy(&cond);pthread_cond_destroy(&cond);return 0; }????上面代碼是用來(lái)創(chuàng)建線程1, 線程2, 同時(shí)線程在條件變量上進(jìn)行等待, 直到有線程將其喚醒, 線程2睡眠一秒, 然后將等待 cond 的線程1喚醒, 此時(shí)線程2被喚醒, 它開(kāi)始執(zhí)行, 執(zhí)行完之后,它有開(kāi)始等待條件變量 cond直到條件變量 cond 滿足時(shí)再醒來(lái).
???????????????????????????????????
????通過(guò)上圖可以看出來(lái), 線程2要活動(dòng), 它必須等待條件變量 cond 滿足時(shí)才能活動(dòng), 即線程2 必須在條件變量上等待, 直到線程 2 將其喚醒
總結(jié)
- 上一篇: 带环迷宫求最短路径
- 下一篇: 进程间关系和守护进程