目錄
1.題目詳情
2.解題思路
2.1.分析題目
2.2.解析思路
3.代碼實現
4.運行結果
1.題目詳情
? ? ? ? 昨天刷抖音,遇到一個面試題,描述如下:
? ? ? ? 請使用兩個線程,分別順序交替打印奇數和偶數,直到10為止。例如有兩個線程,分別為線程1和線程2,線程1首先打印數字1,然后線程2打印數字2,接著線程1再打印數字3,線程2再打印數字4,依次交替運行直到10為止。
2.解題思路
2.1.分析題目
? ? ? ? 乍一看題目很簡單,但是其中涉及了多線程、鎖、線程同步等知識點,如果簡單的使用互斥鎖或者其他的鎖恐怕不會是最好的答案。
2.2.解析思路
? ? ? ? 現在無非要解決兩個問題,第一個問題:線程1需要打印奇數而線程2需要打印偶數;第二個問題:線程1執行完之后需要跳轉到線程2執行。這其中就涉及到了線程切換如何實現,關鍵需要解決第二個問題。
? ? ? ? 拋開第一個問題不談,要解決線程切換的問題,我們先使用互斥鎖實現,采用一個全局變量(標記位)控制兩個線程的執行順序。如果標記位等于某一個值則執行線程1,執行完將標記位置為另一個狀態值,線程2獲取到標記位發生改變,則執行線程2,依次類推。
? ? ? ? 提到這種解題思路,這不就是信號量操作嗎,線程1先執行,然后釋放信號,線程2阻塞等待信號,然后執行。
3.代碼實現
互斥鎖代碼實現:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>pthread_mutex_t lock;
#define TARGET 10
int turn = 1; //1: 表示輪到打印奇數 2: 表示輪到打印偶數//打印奇數
void* print_odd(void* arg) {int num = 1;while (num <= TARGET) {pthread_mutex_lock(&lock);while (turn != 1) {pthread_mutex_unlock(&lock);continue;}printf("thread id:%lu, num:%d\n", pthread_self(), num);turn = 2;pthread_mutex_unlock(&lock);num += 2;}return NULL;
}//打印偶數
void* print_even(void* arg) {int num = 2;while (num <= TARGET) {pthread_mutex_lock(&lock);while (turn != 2) {pthread_mutex_unlock(&lock);continue;}printf("thread id:%lu, num:%d\n", pthread_self(), num);turn = 1;pthread_mutex_unlock(&lock);num += 2;}return NULL;
}int main() {//初始化鎖pthread_mutex_init(&lock, NULL);pthread_t odd_thread, even_thread;//創建線程pthread_create(&odd_thread, NULL, print_odd, NULL);pthread_create(&even_thread, NULL, print_even, NULL);//等待線程結束pthread_join(odd_thread, NULL);pthread_join(even_thread, NULL);//銷毀鎖pthread_mutex_destroy(&lock);return 0;
}
? ? ? ? 打印奇數線程首先運行,turn為標記位,如果標記位為1則打印奇數并修改標記位,如果標記位不是1則釋放鎖等待;打印偶數線程后運行,標記位初始狀態為1,等待標記位,待標記位修改之后,打印偶數。
信號量代碼實現:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <semaphore.h>#define TARGET 10/* 奇數信號量 */
sem_t sem_odd;
/* 偶數信號量 */
sem_t sem_even;static void *print_odd() {int num = 1;while (num <= TARGET) {sem_wait(&sem_odd);printf("thread id:%lu, num:%d\n", pthread_self(), num);num += 2;sem_post(&sem_even);}return NULL;
}static void *print_even() {int num = 2;while (num <= TARGET) {sem_wait(&sem_even);printf("thread id:%lu, num:%d\n", pthread_self(), num);sem_post(&sem_odd);num += 2;}return NULL;
}int main()
{int ret = 0;//將奇數信號量初始值設為1 首先運行ret = sem_init(&sem_odd, 0, 1); if (ret != 0) {printf("init sem_odd failed, ret:%d\n.", ret);return -1;}//將偶數信號量初始值設為0 其次運行ret = sem_init(&sem_even, 0, 0);if (ret != 0) {printf("init sem_even failed, ret:%d\n.", ret);return -1;}pthread_t thread1 = 0;pthread_t thread2 = 0;pthread_create(&thread1, NULL, print_odd, NULL);pthread_create(&thread2, NULL, print_even, NULL);pthread_join(thread1, NULL);pthread_join(thread2, NULL);return 0;
}
? ? ? ? 設置兩個信號量,一個信號量用于控制打印奇數,一個信號量用于控制打印偶數;奇數信號量初始化為1,首先運行,偶數信號量初始化為0,其次運行;打印奇數線程運行完之后發送偶數信號量運行信號,偶數信號量運行完成之后發送奇數信號量運行信號,依次交替打印奇偶數。
4.運行結果
? ? ? ? 兩個線程依次交替打印奇偶數: