中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

怎樣建設(shè)微網(wǎng)站首頁網(wǎng)站數(shù)據(jù)統(tǒng)計工具

怎樣建設(shè)微網(wǎng)站首頁,網(wǎng)站數(shù)據(jù)統(tǒng)計工具,網(wǎng)站名申請,建設(shè)廳建筑業(yè)信息網(wǎng)真假網(wǎng)站Linux系統(tǒng)編程 day09 線程同步 1.互斥鎖2.死鎖3.讀寫鎖4.條件變量(生產(chǎn)者消費者模型)5.信號量 1.互斥鎖 互斥鎖是一種同步機制,用于控制多個線程對共享資源的訪問,確保在同一時間只有一個線程可以訪問特定的資源或執(zhí)行特定的操作…

Linux系統(tǒng)編程 day09 線程同步

  • 1.互斥鎖
  • 2.死鎖
  • 3.讀寫鎖
  • 4.條件變量(生產(chǎn)者消費者模型)
  • 5.信號量

1.互斥鎖

互斥鎖是一種同步機制,用于控制多個線程對共享資源的訪問,確保在同一時間只有一個線程可以訪問特定的資源或執(zhí)行特定的操作。如果沒有互斥鎖,對于多個線程的程序則可能會出現(xiàn)一些未知的問題。比如下面有兩個線程,一個是打印“hello world”的線程,一個是打印“HELLO WORLD”的線程。但是不同的是這個詞匯是分兩次分別打印的,程序代碼如下。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <pthread.h>
#include <time.h>// 打印 hello world
void *mythread1(void *args)
{while(1){printf("hello ");sleep(rand() % 3);printf("world\n");sleep(rand() % 3);}pthread_exit(NULL);
}// 打印HELLO WORLD
void *mythread2(void *args)
{while(1){printf("HELLO ");sleep(rand() % 3);printf("WORLD\n");sleep(rand() % 3);}pthread_exit(NULL);
}int main()
{int ret = 0;pthread_t thread1, thread2;// 初始化隨機數(shù)種子srand(time(NULL));ret = pthread_create(&thread1, NULL, mythread1, NULL);if(ret != 0){printf("pthread_create error: [%s]\n", strerror(ret));return -1;}ret = pthread_create(&thread2, NULL, mythread2, NULL);if(ret != 0){printf("pthread_create error: [%s]\n", strerror(ret));return -1;}// 等待線程結(jié)束pthread_join(thread1, NULL);pthread_join(thread2, NULL);return 0;
}

將上述文件命名為01.pthread_lock.c,使用命令make 01.pthread_lock,則會自動編譯01.pthread_lock.c生成01.pthread_lock,運行該程序可以看到如下現(xiàn)象。

在這里插入圖片描述

可以發(fā)現(xiàn)兩個進(jìn)程打印出來的“hello world”和“HELLO WORLD”并不是連續(xù)在一起的,所以需要加互斥鎖將打印的代碼進(jìn)行加鎖。下面是互斥鎖的一些函數(shù)。


/*** @brief   定義一把互斥鎖*/
pthread_mutex_t mutex_var;/** * @brief   初始化互斥鎖* @param   mutex       互斥鎖* @param   mutexattr   互斥鎖屬性,傳入NULL為默認(rèn)屬性* @return  是否初始化成功,初始化成功返回0,初始化失敗返回錯誤碼* @retval  int*/
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);/** * @brief   互斥鎖加鎖* @param   mutex       互斥鎖* @return  是否加鎖成功,加鎖成功返回0,加鎖失敗會阻塞在這里,發(fā)生錯誤返回錯誤碼* @retval  int*/
int pthread_mutex_lock(pthread_mutex_t *mutex);/** * @brief   互斥鎖嘗試加鎖* @param   mutex       互斥鎖* @return  是否加鎖成功,加鎖成功返回0,加鎖失敗直接返回0,發(fā)生錯誤返回錯誤碼* @retval  int*/
int pthread_mutex_trylock(pthread_mutex_t *mutex);/** * @brief   互斥鎖解鎖* @param   mutex       互斥鎖* @return  是否解鎖成功,解鎖成功返回0,解鎖失敗返回錯誤碼* @retval  int*/
int pthread_mutex_unlock(pthread_mutex_t *mutex);/** * @brief   摧毀互斥鎖* @param   mutex       互斥鎖* @return  摧毀成功返回0,摧毀失敗返回錯誤碼* @retval  int*/
int pthread_mutex_destroy(pthread_mutex_t *mutex);

現(xiàn)在在每個線程運行的函數(shù)中加入互斥鎖,代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <pthread.h>
#include <time.h>// 定義一把互斥鎖
pthread_mutex_t mutex;// 打印 hello world
void *mythread1(void *args)
{while(1){// 加鎖pthread_mutex_lock(&mutex);printf("hello ");sleep(rand() % 3);printf("world\n");sleep(rand() % 3);// 解鎖pthread_mutex_unlock(&mutex);}pthread_exit(NULL);
}// 打印HELLO WORLD
void *mythread2(void *args)
{while(1){// 加鎖pthread_mutex_lock(&mutex);printf("HELLO ");sleep(rand() % 3);printf("WORLD\n");sleep(rand() % 3);// 解鎖pthread_mutex_unlock(&mutex);}pthread_exit(NULL);
}int main()
{int ret = 0;pthread_t thread1, thread2;// 初始化隨機數(shù)種子srand(time(NULL));// 初始化互斥鎖pthread_mutex_init(&mutex, NULL);ret = pthread_create(&thread1, NULL, mythread1, NULL);if(ret != 0){printf("pthread_create error: [%s]\n", strerror(ret));return -1;}ret = pthread_create(&thread2, NULL, mythread2, NULL);if(ret != 0){printf("pthread_create error: [%s]\n", strerror(ret));return -1;}// 等待線程結(jié)束pthread_join(thread1, NULL);pthread_join(thread2, NULL);// 摧毀互斥鎖pthread_mutex_destroy(&mutex);return 0;
}

編譯后運行如下結(jié)果:

在這里插入圖片描述

可以觀察到這次的運行結(jié)果并不會出現(xiàn)線程間交叉打印的情況。

2.死鎖

死鎖是由程序員對互斥鎖的使用不當(dāng)而產(chǎn)生的,并不是操作系統(tǒng)提供的一種機制。死鎖的產(chǎn)生主要由兩種形式。

第一種是自己鎖自己,也就是調(diào)用了兩次加鎖。也就是說線程1加鎖了,再沒釋放鎖的時候線程1又申請加鎖,此時就會產(chǎn)生死鎖,且死鎖阻塞到該位置,還有一種情況是線程1加鎖了,但是線程1的整個程序里面沒有釋放鎖的相關(guān)操作或者根本執(zhí)行不到釋放鎖的代碼,此時若線程2申請加鎖則程序阻塞在此處,若線程1繼續(xù)申請加鎖則阻塞在線程1加鎖處。

第二種是相互鎖住,線程1擁有A鎖請求B鎖,線程2擁有B鎖請求A鎖,這樣就相互阻塞住了。

合理的編寫程序能夠避免死鎖,解決司所有一下一些方法:

  • 1.讓線程按照一定的順序去訪問共享資源。
  • 2.在訪問其它鎖的時候先釋放自己的鎖。
  • 3.調(diào)用pthread_mutex_trylock,該函數(shù)若加鎖不成功會立刻返回,此時就不會造成阻塞死等。

3.讀寫鎖

讀寫鎖也叫共享獨占鎖,讀時共享,寫時獨占,極大地提高了程序運行的效率。也就是當(dāng)讀寫鎖以讀模式鎖住的時候,它是共享的,當(dāng)讀寫鎖以寫模式鎖住的時候,是獨占的。讀寫鎖適合的場景是讀的次數(shù)遠(yuǎn)大于寫的情況下的。

讀寫鎖有以下一些特性:

  • 1.讀寫鎖是寫模式加鎖的時候,在解鎖前所有要對該鎖加鎖的線程都會阻塞。
  • 2.讀寫鎖是讀模式加鎖的時候,如果線程以讀模式加鎖則會成功,以寫模式加鎖會阻塞。
  • 3.讀寫鎖是讀模式加鎖的時候,如果既有讀線程也有寫線程,則嘗試加鎖都會被阻塞。若鎖被釋放,則寫線程會請求鎖成功,而讀線程會繼續(xù)阻塞。也就是讀寫都有的時候優(yōu)先滿足寫模式的鎖,也就是寫比讀優(yōu)先級更高。

下面是讀寫鎖的接口函數(shù):

/*** @brief   定義讀寫鎖變量*/
pthread_rwlock_t rwlock_var;/*** @brief   讀寫鎖初始化* *          初始化讀寫鎖 * @param   rwlock  讀寫鎖* @param   attr    讀寫鎖屬性,傳入NULL為默認(rèn)屬性* @return  初始化成功返回0,反之返回錯誤碼* @retval  int*/
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);/*** @brief   讀寫鎖加讀鎖* @param   rwlock  讀寫鎖* @return  成功加鎖返回0,失敗則返回錯誤碼,鎖被占用則一直阻塞* @retval  int*/
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);/*** @brief   讀寫鎖嘗試加讀鎖* @param   rwlock  讀寫鎖* @return  成功加鎖返回0,失敗則返回錯誤碼,鎖被占用也會直接返回* @retval  int*/
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);/*** @brief   讀寫鎖加寫鎖* @param   rwlock  讀寫鎖* @return  成功加鎖返回0,失敗則返回錯誤碼,鎖被占用則一直阻塞* @retval  int*/
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);/*** @brief   讀寫鎖嘗試加寫鎖* @param   rwlock  讀寫鎖* @return  成功加鎖返回0,失敗則返回錯誤碼,鎖被占用也會直接返回* @retval  int*/
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);/*** @brief   讀寫鎖解鎖* @param   rwlock  讀寫鎖* @return  成功解鎖返回0,失敗則返回錯誤碼* @retval  int*/
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);/*** @brief   摧毀讀寫鎖* @param   rwlock  讀寫鎖* @return  成功摧毀返回0,失敗則返回錯誤碼* @retval  int*/
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

下面舉一個關(guān)于讀寫鎖的例子,有3個寫線程,5個讀線程,寫線程修改數(shù)字,讀線程讀取數(shù)字輸出到終端。代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <pthread.h>// 線程總數(shù)
#define     THREAD_COUNT    8// 定義讀寫鎖
pthread_rwlock_t rwlock;// 計數(shù)
int number = 0;// 讀線程回調(diào)函數(shù)
void *thread_read(void *args)
{int i = *(int *)args;int cur;while(1){// 讀寫鎖加讀鎖pthread_rwlock_rdlock(&rwlock);cur = number;printf("[%d]-R: [%d]\n", i, cur);// 讀寫鎖加寫鎖pthread_rwlock_unlock(&rwlock);sleep(rand() % 3);}
}// 寫線程回調(diào)函數(shù)
void *thread_write(void *args)
{int i = *(int *)args;int cur;while(1){// 讀寫鎖加寫鎖pthread_rwlock_wrlock(&rwlock);cur = number;cur += 1;number = cur;printf("[%d]-W: [%d]\n", i, cur);// 讀寫鎖解鎖pthread_rwlock_unlock(&rwlock);sleep(rand() % 3);}
}int main()
{int ret = 0;int arr[THREAD_COUNT];  // 記錄第幾個線程pthread_t threads[THREAD_COUNT];    // 線程數(shù)組// 初始化隨機數(shù)種子srand(time(NULL));// 初始化讀寫鎖pthread_rwlock_init(&rwlock, NULL);// 創(chuàng)建3個寫線程for(int i = 0; i < 3; i++){arr[i] = i;ret = pthread_create(&threads[i], NULL, thread_write, &arr[i]);if(ret != 0){printf("pthread_create error: [%s]\n", strerror(ret));return -1;}}// 創(chuàng)建5個讀線程for(int i = 3; i < THREAD_COUNT; i++){arr[i] = i;ret = pthread_create(&threads[i], NULL, thread_read, &arr[i]);if(ret != 0){printf("pthread_create error: [%s]\n", strerror(ret));return -1;}}// 回收子線程for(int i = 0; i < THREAD_COUNT; i++){pthread_join(threads[i], NULL);}// 釋放鎖pthread_rwlock_destroy(&rwlock);return 0;
}

編譯程序運行的結(jié)果如下:

在這里插入圖片描述

可以發(fā)現(xiàn)讀線程輸出的數(shù)字都是寫線程修改后的,并不會出現(xiàn)讀線程的數(shù)據(jù)是不符合寫進(jìn)程修改后的。如果沒有加讀寫鎖,則會讓讀寫亂套,當(dāng)寫線程修改完數(shù)據(jù)之后讀線程也可能正好輸出修改前的值。

4.條件變量(生產(chǎn)者消費者模型)

條件變量主要是用于生產(chǎn)者消費者模型的。所謂生產(chǎn)者消費者模型就是生產(chǎn)者負(fù)責(zé)生成東西,而消費者負(fù)責(zé)對生產(chǎn)者生產(chǎn)者的東西用于消費。在這種情況下,生產(chǎn)者消費的東西其實也就是臨界資源,所以需要使用互斥鎖進(jìn)行訪問。而在生產(chǎn)者消費者模型中無法確定是生產(chǎn)者先訪問還是消費者先訪問,所以在生產(chǎn)者沒有生產(chǎn)東西的時候消費者也可能需要進(jìn)行消費,或者生產(chǎn)者生產(chǎn)的進(jìn)度會更不上消費者消耗的進(jìn)度。因此,為了保證消費者每次消費都是在生產(chǎn)者生成東西之后或者生產(chǎn)的東西有剩余,所以需要使用到條件變量,此時原來并行的生產(chǎn)者消費者就變成了串行的生產(chǎn)者消費者。關(guān)于條件變量的接口如下:

/*** @brief   條件變量定義,定義一個條件變量*/
pthread_cond_t cond_var;/*** @brief   初始化條件變量* @param   cond        條件變量* @param   cond_attr   條件變量屬性,傳入NULL為默認(rèn)屬性* @return  初始化成功返回0,失敗返回錯誤碼* @retval  int*/ 
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);/*** @brief   喚醒至少一個阻塞在該條件變量上的線程* @param   cond    條件變量* @return  喚醒成功返回0,失敗返回0* @retval  int*/ 
int pthread_cond_signal(pthread_cond_t *cond);/*** @brief   喚醒所有阻塞在該條件變量上的線程* @param   cond    條件變量* @return  喚醒成功返回0,失敗返回0* @retval  int*/ 
int pthread_cond_broadcast(pthread_cond_t *cond);/*** @brief   阻塞等待條件變量滿足* *          當(dāng)條件變量不滿足的時候,會阻塞線程并進(jìn)行解鎖*          當(dāng)條件變量滿足的時候,會解除線程阻塞并加鎖* @param   cond    條件變量* @param   mutex   互斥鎖* @return  成功返回0,失敗返回0* @retval  int*/ 
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);/*** @brief   銷毀條件變量* @param   cond    條件變量* @return  銷毀成功返回0,失敗返回0* @retval  int*/ 
int pthread_cond_destroy(pthread_cond_t *cond);

需要注意的是條件變量本身并不是鎖,但是它可以造成線程的阻塞,所以通常需要與互斥鎖配合使用。使用互斥鎖是為了保護共享數(shù)據(jù),使用條件變量可以使線程阻塞,等待某個條件的發(fā)生,當(dāng)條件滿足的時候解除阻塞。

下面給一個關(guān)于生產(chǎn)者消費者的例子,有一個鏈表,生產(chǎn)者負(fù)責(zé)不斷地從堆區(qū)申請空間開辟內(nèi)存并且存入數(shù)據(jù)并將節(jié)點放到鏈表上,而消費者負(fù)責(zé)在鏈表上不斷地讀取數(shù)據(jù)并且釋放節(jié)點,代碼如下所示。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>// 鏈表節(jié)點定義
typedef struct node
{int data;struct node *next;
} node_t;// 互斥鎖
pthread_mutex_t mutex;
// 條件變量
pthread_cond_t cond;
// 頭結(jié)點
node_t *head = NULL;// 生產(chǎn)者線程
void *thread_product(void *args)
{while(1){// 申請節(jié)點node_t *pnode = (node_t *)malloc(sizeof(node_t));if(pnode == NULL){perror("malloc error");exit(-1);}pnode->data = rand() % 1000;// 加互斥鎖pthread_mutex_lock(&mutex);pnode->next = head;head = pnode;printf("[Productor]: %d\n", pnode->data);// 解鎖pthread_mutex_unlock(&mutex);// 通知消費者線程pthread_cond_signal(&cond);sleep(rand() % 3);}pthread_exit(NULL);
}// 消費者線程
void *thread_consume(void *args)
{while(1){// 加互斥鎖pthread_mutex_lock(&mutex);if(head == NULL){// 條件滿足解除阻塞并加鎖// 條件不滿足阻塞并解鎖pthread_cond_wait(&cond, &mutex);}node_t *pnode = head;head = pnode->next;printf("[Consumer]: %d\n", pnode->data);free(pnode);pnode = NULL;// 解鎖pthread_mutex_unlock(&mutex);sleep(rand() % 3);}pthread_exit(NULL);
}int main()
{int ret;// 生產(chǎn)者與消費者線程pthread_t thread_productor, thread_consumer;// 初始化隨機數(shù)種子srand(time(NULL));// 初始化條件變量與互斥鎖pthread_mutex_init(&mutex, NULL);pthread_cond_init(&cond, NULL);ret = pthread_create(&thread_productor, NULL, thread_product, NULL);if(ret != 0){printf("pthread_create error: [%s]\n", strerror(ret));return -1;}ret = pthread_create(&thread_consumer, NULL, thread_consume, NULL);if(ret != 0){printf("pthread_create error: [%s]\n", strerror(ret));return -1;}// 回收線程pthread_join(thread_productor, NULL);pthread_join(thread_consumer, NULL);// 銷毀互斥鎖與條件變量pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);return 0;
}

運行可以發(fā)現(xiàn)消費者消費的是生產(chǎn)者最后一次生產(chǎn)出來的。

在這里插入圖片描述
如果將上述的代碼改為多個消費者線程和多個生產(chǎn)者線程的時候,則上述的代碼就會出現(xiàn)Segmentation fault (core dumped)的情況。首先需要分析這個問題是如何產(chǎn)生的。這個問題的原因就是訪問了非法的空間內(nèi)存,而這種情況只會在消費者線程中出現(xiàn)。而經(jīng)過定位可以發(fā)現(xiàn)對NULL指針進(jìn)行了操作,也就是head = pnode->next; printf("[Consumer]: %d\n", pnode->data);。首先在生產(chǎn)者線程中調(diào)用了pthread_cond_signal函數(shù)的時候會通知一個或者多個消費者線程喚醒滿足,而此時這幾個線程都不在處于阻塞狀態(tài),就會進(jìn)行解鎖,當(dāng)連續(xù)多個消費者線程依次解鎖的時候向下運行就會導(dǎo)致訪問到非法空間。比如鏈表中只有一個節(jié)點,而此時有三個消費者線程處于阻塞狀態(tài)且阻塞在pthread_cond_wait處。此時生產(chǎn)者線程調(diào)用了pthread_cond_signal則會喚醒這消費者三個線程的一個或者是兩個,又或者是三個。此時三個的條件變量都滿足,第一個消費者線程搶到了鎖消費了一個結(jié)點。而此時生產(chǎn)者線程沒有創(chuàng)造新的節(jié)點,由于第二個線程已經(jīng)滿足了條件變量,此時它搶到了互斥鎖,則也會向下執(zhí)行,由于前面的線程已經(jīng)消費了唯一的一個線程,所以此時就會訪問到非法的內(nèi)存空間。應(yīng)對這種情況則是在pthread_cond_wait后面對頭結(jié)點再一次進(jìn)行判斷,若滿足條件則向下執(zhí)行,不滿足條件則解鎖并使用continue進(jìn)入下一次循環(huán)。以5個生產(chǎn)者線程10個消費者線程為例,代碼如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <string.h>// 線程數(shù)量
#define     PRODUCER_THREAD_COUNT     5         // 生產(chǎn)線程數(shù)量
#define     CONSUMER_THREAD_COUNT     10        // 消費線程數(shù)量// 鏈表節(jié)點
struct node 
{int data;struct node *next;
};// 頭結(jié)點
struct node *head = NULL;// 互斥鎖
pthread_mutex_t mutex;// 條件變量
pthread_cond_t cond;void *thread_producer(void *arg)
{struct node *pnode = NULL;int idx = (int)(long)arg;while(1){pnode = (struct node *)malloc(sizeof(struct node));if(pnode == NULL){perror("malloc error");exit(-1);}pnode->data = rand() % 100;// 加鎖pthread_mutex_lock(&mutex);pnode->next = head;head = pnode;printf("P[%d]: %d\n", idx, pnode->data);pthread_mutex_unlock(&mutex);pthread_cond_signal(&cond);sleep(rand() % 3);}pthread_exit(NULL);
}void *thread_consumer(void *arg)
{struct node *pnode = NULL;int idx = (int)(long)arg;while(1){   pthread_mutex_lock(&mutex);if(head == NULL){pthread_cond_wait(&cond, &mutex);}// 若頭節(jié)點為空if(head == NULL){// 解鎖pthread_mutex_unlock(&mutex);continue;}pnode = head;head = head->next;printf("C[%d]: %d\n", idx, pnode->data);pthread_mutex_unlock(&mutex);free(pnode);pnode = NULL;sleep(rand() % 3);}pthread_exit(NULL);
}int main()
{int ret = 0;pthread_t producer_thread[PRODUCER_THREAD_COUNT], consumer_thread[CONSUMER_THREAD_COUNT];srand((unsigned int)time(NULL));// 初始化互斥鎖pthread_mutex_init(&mutex, NULL);// 初始化條件變量pthread_cond_init(&cond, NULL);// 創(chuàng)建生產(chǎn)者線程for(int i = 1; i <= PRODUCER_THREAD_COUNT; i++){ret = pthread_create(&producer_thread[i - 1], NULL, thread_producer, (void *)(long)i);if(ret != 0){printf("pthread_create error: %s\n", strerror(ret));exit(-1);}}// 創(chuàng)建消費者線程for(int i = 1; i <= CONSUMER_THREAD_COUNT; i++){ ret = pthread_create(&consumer_thread[i - 1], NULL, thread_consumer, (void *)(long)i);if(ret != 0){printf("pthread_create error: %s\n", strerror(ret));exit(-1);}}// 回收線程for(int i = 0; i < PRODUCER_THREAD_COUNT; i++){pthread_join(producer_thread[i], NULL);}for(int i = 0; i < CONSUMER_THREAD_COUNT; i++){pthread_join(consumer_thread[i], NULL);}// 摧毀互斥鎖pthread_mutex_destroy(&mutex);return 0;
}

運行結(jié)果如下:

在這里插入圖片描述

5.信號量

信號量可以理解為是升級版的互斥鎖,因為互斥鎖只能運行一個線程進(jìn)行訪問,而信號量可以支持多個線程或者進(jìn)程。關(guān)于信號量的接口如下所示:

/*** @brief   定義信號量*/
sem_t sem_var;/*** @brief   初始化信號量* @param   sem     信號量* @param   pshared 0表示線程同步,1表示進(jìn)程同步* @param   value   最多有多少個線程操作共享數(shù)據(jù)* @return  成功返回0,失敗返回-1,并設(shè)置errno的值。* @retval  int*/
int sem_init(sem_t *sem, int pshared, unsigned int value);/*** @brief   相當(dāng)于sem--,當(dāng)sem為0的時候,引起阻塞,即加鎖。* @param   sem     信號量* @return  成功返回0,失敗返回-1,并設(shè)置error的值* @retval  int*/
int sem_wait(sem_t *sem);/*** @brief   與sem_wait一樣,但是不會阻塞* @param   sem     信號量* @return  成功返回0,失敗返回-1,并設(shè)置error的值* @retval  int*/
int sem_trywait(sem_t *sem);/*** @brief   相當(dāng)于sem++* @param   sem     信號量* @return  成功返回0,失敗返回-1,并設(shè)置errno的值* @retval  int*/
int sem_post(sem_t *sem);/*** @brief   摧毀信號量* @param   sem     信號量* @return  成功返回0,失敗返回-1,并設(shè)置errno的值*/
int sem_destroy(sem_t *sem);

什么時候用信號量呢?也就是當(dāng)一個共享資源能夠被多個現(xiàn)成進(jìn)行操作的時候。比如停車場,里面會有很多個車位,可以同時允許多個車位進(jìn)行???#xff0c;代碼如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>// 車位數(shù)量
#define     PARKING_COUNT      10// 線程數(shù)量
#define     ENTRY_PARKING_THREAD_COUNT      10          // 進(jìn)入停車場線程
#define     EXIT_PARKING_THREAD_COUNT       10          // 離開停車場線程// 結(jié)點模擬停車場
struct park 
{int use;                    // 是否被使用int parking_space;          // 停車位編號int license_plate_number;   // 停車車牌號
}park[PARKING_COUNT];// 信號量
sem_t entry_sem;    // 進(jìn)入停車場信號量
sem_t exit_sem;     // 離開停車場信號量// 進(jìn)入停車場線程
void *thread_entryParking(void *arg)
{// 標(biāo)記是否停車int parking_space = -1;int license_plate_number = 0;while(1){// 車位標(biāo)志parking_space = 0;license_plate_number = rand() % 10000 + 10000;printf("車牌號[%d]駛來了\n", license_plate_number);sleep(rand() % 5);// 開始停車sem_wait(&entry_sem);// 尋找車位for(int i = 0; i < PARKING_COUNT; i++){if(park[i].use == 0){parking_space = park[i].parking_space;break;}}// 沒有找到停車位if(parking_space == 0){sem_post(&entry_sem);printf("車牌號[%d]因為沒有車位離開了\n", license_plate_number);continue;}// 開始停車park[parking_space - 1].license_plate_number = license_plate_number;park[parking_space - 1].use = 1;printf("車牌號[%d]停進(jìn)了停車場的[%d]車位\n", license_plate_number, park[parking_space - 1].parking_space);// 通知可以有車離開sem_post(&exit_sem);}pthread_exit(NULL);
}// 離開停車場
void *thread_exitParking(void *arg)
{// 車位int parking_space = 0;while(1){sleep(rand() % 5);// 隨機車位parking_space = rand() % PARKING_COUNT + 1;sem_wait(&exit_sem);// 該車位沒有車?yán)^續(xù)下一次if(park[parking_space - 1].use == 0){sem_post(&exit_sem);continue;}printf("車牌號[%d]離開了停車場的[%d]車位\n", park[parking_space - 1].license_plate_number, park[parking_space - 1].parking_space);// 標(biāo)記車位沒有使用park[parking_space - 1].use = 0;// 可停車數(shù)加1sem_post(&entry_sem);}pthread_exit(NULL);
}int main()
{int ret = 0;// 進(jìn)入停車場線程pthread_t entryParking_thread[ENTRY_PARKING_THREAD_COUNT];// 離開停車場線程pthread_t exitParking_thread[EXIT_PARKING_THREAD_COUNT];srand((unsigned int)time(NULL));// 初始化信號量sem_init(&entry_sem, 0, PARKING_COUNT);sem_init(&exit_sem, 0, 0);// 初始化停車場memset(&park, 0x00, sizeof park);for(int i = 0; i < PARKING_COUNT; i++){park[i].parking_space = i + 1;}// 創(chuàng)建停車線程for(int i = 0; i < ENTRY_PARKING_THREAD_COUNT; i++){ret = pthread_create(&entryParking_thread[i], NULL, thread_entryParking, NULL);if(ret != 0){printf("pthread_create error: %s\n", strerror(ret));exit(-1);}}// 創(chuàng)建離開停車場線程for(int i = 0; i < EXIT_PARKING_THREAD_COUNT; i++){ret = pthread_create(&exitParking_thread[i], NULL, thread_exitParking, NULL);if(ret != 0){printf("pthread_create error: %s\n", strerror(ret));exit(-1);}}// 回收線程for(int i = 0; i < ENTRY_PARKING_THREAD_COUNT; i++){pthread_join(entryParking_thread[i], NULL);}for(int i = 0; i < EXIT_PARKING_THREAD_COUNT; i++){pthread_join(exitParking_thread[i], NULL);}// 摧毀信號量sem_destroy(&entry_sem);sem_destroy(&exit_sem);return 0;
}

運行上述代碼,結(jié)果如下:

在這里插入圖片描述

http://www.risenshineclean.com/news/37675.html

相關(guān)文章:

  • 記事本做網(wǎng)站格式外貿(mào)seo公司
  • 20g虛擬主機建設(shè)網(wǎng)站b站推廣網(wǎng)站入口202
  • 域名換了網(wǎng)站需要備案么鄭州seo代理公司
  • 程序員做的導(dǎo)航網(wǎng)站平臺推廣怎么做
  • 牌具網(wǎng)站廣告怎么做云優(yōu)客seo排名公司
  • 微博分享的網(wǎng)站怎么做亞洲衛(wèi)星電視網(wǎng)參數(shù)表
  • 冷色網(wǎng)站鄭州seo價格
  • 焦作河南網(wǎng)站建設(shè)品牌策略
  • 自己做新聞網(wǎng)站找客戶的十大方法
  • 網(wǎng)頁游戲開服表怎么關(guān)閉班級優(yōu)化大師使用指南
  • 做網(wǎng)站素材在哪里找網(wǎng)站seo平臺
  • 網(wǎng)站建設(shè)公司的運營方式中國足彩網(wǎng)競彩推薦
  • 中國城鄉(xiāng)住房和建設(shè)部網(wǎng)站首頁如何快速推廣自己的品牌
  • 珠海網(wǎng)站建站流量寶
  • 做網(wǎng)站是什么鬼做國外網(wǎng)站
  • 做獨立網(wǎng)站給你百度競價推廣方案的制定
  • 做網(wǎng)站百度新聞源合肥關(guān)鍵詞排名
  • 國際貿(mào)易網(wǎng)站排名最新網(wǎng)絡(luò)營銷方式有哪些
  • 做網(wǎng)站虛擬主機怎么選擇技成培訓(xùn)網(wǎng)
  • 建網(wǎng)站的軟件優(yōu)幫云網(wǎng)站設(shè)計制作在哪里找
  • 網(wǎng)站商城系統(tǒng)建設(shè)方案新媒體運營主要做什么
  • 企業(yè)網(wǎng)站宣傳冊應(yīng)該哪個部門做it培訓(xùn)機構(gòu)
  • net開發(fā)的網(wǎng)站開發(fā)網(wǎng)站seo優(yōu)化排名
  • 溫州專業(yè)網(wǎng)站建設(shè)西安seo排名
  • 成都廣告公司排名前十名蘇州首頁排名關(guān)鍵詞優(yōu)化
  • 學(xué)做網(wǎng)站論壇vip賬戶蘇州網(wǎng)站建設(shè)書生
  • 無錫專業(yè)做網(wǎng)站站長網(wǎng)站查詢工具
  • 高唐網(wǎng)站建設(shè)電子商務(wù)網(wǎng)站建設(shè)的步驟
  • 深圳微商城網(wǎng)站制作費用網(wǎng)站seo排名優(yōu)化工具
  • 網(wǎng)站關(guān)鍵詞seo優(yōu)化怎么做怎樣進(jìn)行seo優(yōu)化