爲使系統中的多線程能有條不紊地運行,在系統中必須提供用於實現線程間同步和通信的機制。爲了支持不同頻率的交互操作和不同程度的並行性,在多線程OS中通常提供多種同步機制,如互斥鎖、條件變量、計數信號量以及多讀、單寫鎖等,下面就以互斥鎖爲例實現線程同步。
其中, 程序中有兩個線程,A、B , 線程A是主線程,主要負責讀取用戶從終端中輸入的字符串;而線程B是新建的線程,主要用於判斷讀取的字符串是否爲結束符,如果不是,則向終端打印出剛纔輸入的字符串的長度並等待再次輸入,否則結束程序。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
void *thread_function(void *arg);
pthread_mutex_t work_mutex;
int time_to_exit=0; /*互斥量,保護工作區及額外變量time_to_exit*/
#define WORK_SIZE 1024
char work_area[WORK_SIZE]; /*工作區*/
int main()
{
int res ;
pthread_t a_thread;
void *thread_result;
res = pthread_mutex_init(&work_mutex,NULL); /*初始化工作區*/
if(res!=0){
perror("Mutex initialization failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&a_thread,NULL,thread_function,NULL); /*創建新線程*/
if(res!=0){
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
/*主線程A*/
pthread_mutex_lock(&work_mutex); //主線程對互斥量加鎖
printf("Input some text. Enter 'end' to finish\n");
while(!time_to_exit){//當線程B遇到結束符後會將變量置爲非零以結束循環
fgets(work_area,WORK_SIZE,stdin); //從終端向工作區中輸入字符串
pthread_mutex_unlock(&work_mutex); //解鎖互斥量
while(1){
pthread_mutex_lock(&work_mutex); // 這裏必須等待線程B釋放後才能加鎖,否則只能一直等待
if(work_area[0]!='\0'){
pthread_mutex_unlock(&work_mutex);
sleep(1);
}else{
break;
}
}
}
pthread_mutex_unlock(&work_mutex);
printf("\nWaiting for thread to finish...\n");
res = pthread_join(a_thread,&thread_result); //父線程等待子線程終止
if(res!=0){
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joined\n");
pthread_mutex_destroy(&work_mutex);
exit(EXIT_SUCCESS);
}
/*新線程B*/
void *thread_function(void *arg)
{
sleep(1);
pthread_mutex_lock(&work_mutex);//等待線程A讀取字符串並解鎖後將互斥量加鎖,以獲取工作區資源
while(strncmp("end",work_area,3)!=0){//判斷是否遇到結束符end
printf("You input %d characters\n",strlen(work_area)-1);
work_area[0]='\0';
pthread_mutex_unlock(&work_mutex);
sleep(1);
pthread_mutex_lock(&work_mutex);
while(work_area[0]=='\0'){//通過將第一個字符設置爲NULL,通知線程A已完成字符統計
pthread_mutex_unlock(&work_mutex);//解鎖互斥量並等待線程A繼續運行
sleep(1);
pthread_mutex_lock(&work_mutex);
}
}
time_to_exit = 1;
work_area[0] = '\0' ;
pthread_mutex_unlock(&work_mutex);
pthread_exit(0);
}
在該程序中,新線程首先試圖對互斥量加鎖。如果它已經被加鎖,這個調用將被阻塞直到鎖被釋放爲止。一旦獲得訪問權,新線程將檢查是否有申請退出程序的請求。如果有,就簡單設置time_to_exit變量,再把工作區的第一個字符設置爲'\0',然後退出。如果不想退出,就對字符個數進行統計。然後把work_area數組中的第一個字符設置爲'\0'。通過將第一個字符設置爲NULL,通知線程A已完成字符統計。隨後解鎖互斥量並等待主線程繼續運行。程序將週期性地嘗試給互斥量加鎖,如加鎖成功,則檢查主線程是否又有字符串需要統計。如沒有,則解鎖互斥量繼續等待;否則將統計字符個數,並再次進入循環。