Linux系統(tǒng)編程-(pthread)線程通信(互斥鎖)

      網(wǎng)友投稿 1382 2025-03-31

      這篇文章介紹linux下線程同步與互斥機制–互斥鎖,在多線程并發(fā)的時候,都會出現(xiàn)多個消費者取數(shù)據(jù)的情況,這種時候數(shù)據(jù)都需要進行保護,比如: 火車票售票系統(tǒng)、汽車票售票系統(tǒng)一樣,總票數(shù)是固定的,但是購票的終端非常多。

      互斥鎖就是用來保護某一個資源不能同時被2個或者2個以上的線程使用。

      為什么需要加鎖?

      就是因為多個線程共用進程的資源,要訪問的是公共區(qū)間時(全局變量),當一個線程訪問的時候,需要加上鎖以防止另外的線程對它進行訪問,以實現(xiàn)資源的獨占。在一個時刻只能有一個線程掌握某個互斥鎖,擁有上鎖狀態(tài)的線程才能夠對共享資源進行操作。若其他線程希望上鎖一個已經(jīng)上鎖了的互斥鎖,則該線程就會掛起,直到上鎖的線程釋放掉互斥鎖為止。

      1. 互斥鎖介紹

      在編程中,引入了對象互斥鎖的概念,來保證共享數(shù)據(jù)操作的完整性。每個對象都對應于一個可稱為" 互斥鎖" 的標記,這個標記用來保證在任一時刻,只能有一個線程訪問該對象。

      linux系統(tǒng)下定義了一套專門用于線程互斥的mutex函數(shù)。

      mutex 是一種簡單的加鎖的方法來控制對共享資源的存取,這個互斥鎖只有兩種狀態(tài)(上鎖和解鎖),可以把互斥鎖看作某種意義上的全局變量。

      總結: 互斥鎖可以保護某個資源同時只能被一個線程所使用。

      2. 互斥鎖相關的函數(shù)

      #include //銷毀互斥鎖 int pthread_mutex_destroy(pthread_mutex_t *mutex); //初始化互斥鎖 int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr); //上鎖: 阻塞方式 int pthread_mutex_lock(pthread_mutex_t *mutex); //上鎖: 非阻塞方式 int pthread_mutex_trylock(pthread_mutex_t *mutex); //解鎖 int pthread_mutex_unlock(pthread_mutex_t *mutex); 說明: 對于Linux下的信號量/讀寫鎖文件進行編譯,需要在編譯選項中指明-D_GNU_SOURCE 否則用gcc編譯就會出現(xiàn) PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP未聲明(在此函數(shù)內第一次使用) 這樣的提示。 例如: $ gcc app.c -lpthread -D_GNU_SOURCE

      2.1 初始化互斥鎖

      頭文件 #include 定義函數(shù) int pthread_mutex_init( pthread_mutex_t *mutex, const pthread_mutex_attr_t* attr ); 函數(shù)說明 該函數(shù)初始化一個互斥體變量,如果參數(shù)attr 為NULL,則互斥體變量mutex 使用默認的屬性。

      2.2 銷毀互斥鎖

      頭文件 #include 定義函數(shù) int pthread_mutex_destroy ( pthread_mutex_t *mutex ); 函數(shù)說明 該函數(shù)用來釋放分配給參數(shù)mutex 的資源。 返回值 調用成功時返回值為 0, 否則返回一個非0 的錯誤代碼。

      2.3 上鎖

      頭文件 #include 定義函數(shù) int pthread_mutex_lock( pthread_mutex_t *mutex ); 函數(shù)說明 該函數(shù)用來鎖住互斥體變量。如果參數(shù)mutex 所指的互斥體已經(jīng)被鎖住了,那么發(fā)出調用的線程將被阻塞直到其他線程對mutex 解鎖。 如果上鎖成功,將返回0。

      2.4 嘗試上鎖-非阻塞

      表頭文件 #include 定義函數(shù) int pthread_mutex_trylock( pthread_t *mutex ); 函數(shù)說明 該函數(shù)用來鎖住mutex 所指定的互斥體,但不阻塞。 返回值 如果該互斥體已經(jīng)被上鎖,該調用不會阻塞等待,而會返回一個錯誤代碼。 如果上鎖成功,將返回0.

      2.5 解鎖

      頭文件 #include 定義函數(shù) int pthread_mutex_unlock( pthread_mutex_t *mutex ); 函數(shù)說明 該函數(shù)用來對一個互斥體解鎖。如果當前線程擁有參數(shù)mutex 所指定的互斥體,該調用將該互斥體解鎖。 如果解鎖成功,將返回0. 說明: 對同一個鎖多次解鎖沒有疊加效果,如果鎖是上鎖狀態(tài),那么多次解鎖也只有一次有效。

      3. 互斥鎖框架運用模型

      pthread_mutex_t mutex; void 線程1(void) { while(1) { //上鎖 pthread_mutex_lock(&mutex); .....主體代碼...... //解鎖 pthread_mutex_unlock(&mutex); } } void 線程2(void) { while(1) { //上鎖 pthread_mutex_lock(&mutex); .....主體代碼...... //解鎖 pthread_mutex_unlock(&mutex); } } int main(void) { //初始化互斥鎖 pthread_mutex_init(&mutex,NULL); .....主體代碼...... //銷毀互斥鎖 pthread_mutex_destroy(&mutex); }

      4. 案例代碼: 對公共函數(shù)上鎖保護

      下面代碼是兩個線程同時調用了一個打印函數(shù),分別打印: “123” “456”。

      void print(char *p) { while(*p!='

      void print(char *p) { while(*p!='\0') { printf("%c",*p++); sleep(1); } } void *thread1_func(void *arg) { print("123\n"); } void *thread2_func(void *arg) { print("456\n"); }

      ') { printf("%c",*p++); sleep(1); } } void *thread1_func(void *arg) { print("123\n"); } void *thread2_func(void *arg) { print("456\n"); }

      如果不保護,默認的打印結果:

      [wbyq@wbyq linux-share-dir]$ ./a.out 412536

      預期的結果應該是打印1236連續(xù)在一起的,對于這種情況,就可以加鎖進行保護。

      上鎖的示例代碼:

      #include #include #include #include #include #include #include #include #include pthread_mutex_t mutex; void print(char *p) { while(*p!='

      #include #include #include #include #include #include #include #include #include pthread_mutex_t mutex; void print(char *p) { while(*p!='\0') { printf("%c",*p++); sleep(1); } } /* 線程工作函數(shù) */ void *thread_work_func(void *dev) { while(1) { //上鎖 pthread_mutex_lock(&mutex); print("123\n"); //解鎖 pthread_mutex_unlock(&mutex); usleep(1000*10); } } /* 線程工作函數(shù) */ void *thread_work_func2(void *dev) { //上鎖 pthread_mutex_lock(&mutex); print("456\n"); //解鎖 pthread_mutex_unlock(&mutex); usleep(1000*10); } int main(int argc,char **argv) { //初始化互斥鎖 pthread_mutex_init(&mutex,NULL); /*1. 創(chuàng)建子線程1*/ pthread_t thread_id; if(pthread_create(&thread_id,NULL,thread_work_func,NULL)!=0) { printf("子線程1創(chuàng)建失敗.\n"); return -1; } /*2. 創(chuàng)建子線程2*/ pthread_t thread_id2; if(pthread_create(&thread_id2,NULL,thread_work_func2,NULL)!=0) { printf("子線程2創(chuàng)建失敗.\n"); return -1; } /*3. 等待線程的介紹*/ pthread_join(thread_id,NULL); pthread_join(thread_id2,NULL); //銷毀互斥鎖 pthread_mutex_destroy(&mutex); return 0; }

      ') { printf("%c",*p++); sleep(1); } } /* 線程工作函數(shù) */ void *thread_work_func(void *dev) { while(1) { //上鎖 pthread_mutex_lock(&mutex); print("123\n"); //解鎖 pthread_mutex_unlock(&mutex); usleep(1000*10); } } /* 線程工作函數(shù) */ void *thread_work_func2(void *dev) { //上鎖 pthread_mutex_lock(&mutex); print("456\n"); //解鎖 pthread_mutex_unlock(&mutex); usleep(1000*10); } int main(int argc,char **argv) { //初始化互斥鎖 pthread_mutex_init(&mutex,NULL); /*1. 創(chuàng)建子線程1*/ pthread_t thread_id; if(pthread_create(&thread_id,NULL,thread_work_func,NULL)!=0) { printf("子線程1創(chuàng)建失敗.\n"); return -1; } /*2. 創(chuàng)建子線程2*/ pthread_t thread_id2; if(pthread_create(&thread_id2,NULL,thread_work_func2,NULL)!=0) { printf("子線程2創(chuàng)建失敗.\n"); return -1; } /*3. 等待線程的介紹*/ pthread_join(thread_id,NULL); pthread_join(thread_id2,NULL); //銷毀互斥鎖 pthread_mutex_destroy(&mutex); return 0; }

      Linux系統(tǒng)編程-(pthread)線程通信(互斥鎖)

      5. 案例代碼: 模擬火車票售賣系統(tǒng)(保護同一個全局變量)

      下面代碼模擬一個火車票售賣系統(tǒng),此處不加鎖,可能會出現(xiàn)賣出負數(shù)票的情況。

      #include #include int cnt = 121; //火車票,公共資源(全局) void* pthread1(void* args) { while(ticketcount > 0) { printf("窗口A開始售票,門票是:%d\n",cnt); sleep(2); cnt--; printf("窗口A售票結束,最后一張車票是:%d\n",cnt); } } void* pthread2(void* args) { while(cnt > 0) { printf("窗口B開始售票,車票是:%d\n",cnt); sleep(2); cnt--; printf("窗口B售票結束,最后一張車票是:%d\n",cnt); } } int main() { pthread_t pthid1 = 0; pthread_t pthid2 = 0; pthread_create(&pthid1,NULL,pthread1,NULL); pthread_create(&pthid2,NULL,pthread2,NULL); pthread_join(pthid1,NULL); pthread_join(pthid2,NULL); return 0; }

      加鎖之后的火車售票系統(tǒng)

      #include #include int cnt = 121; pthread_mutex_t lock; void* pthread1(void* args) { while(1) { pthread_mutex_lock(&lock); //因為要訪問全局的共享變量,所以就要加鎖 if(cnt > 0) //如果有票 { printf("窗口A開始售票,車票是:%d\n",cnt); sleep(2); cnt--; printf("窗口A售票結束,最后一張車票是:%d\n",cnt); } else { pthread_mutex_unlock(&lock); pthread_exit(NULL); } pthread_mutex_unlock(&lock); sleep(1); //要放到鎖的外面,讓另一個有時間鎖 } } void* pthread2(void* args) { while(1) { pthread_mutex_lock(&lock); if(cnt>0) { printf("窗口B開始售票--車票是:%d\n",cnt); sleep(2); cnt--; printf("窗口B售票結束,最后一張車票是:%d\n",cnt); } else { pthread_mutex_unlock(&lock); pthread_exit(NULL); } pthread_mutex_unlock(&lock); sleep(1); } } int main() { pthread_t pthid1 = 0; pthread_t pthid2 = 0; //初始化鎖 pthread_mutex_init(&lock,NULL); //創(chuàng)建線程 pthread_create(&pthid1,NULL,pthread1,NULL); pthread_create(&pthid2,NULL,pthread2,NULL); //等待線程結束 pthread_join(pthid1,NULL); pthread_join(pthid2,NULL); //銷毀鎖 pthread_mutex_destroy(&lock); return 0; }

      Linux 任務調度

      版權聲明:本文內容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內刪除侵權內容。

      上一篇:excel如何插入絕對值符號(絕對值符號怎么輸入excel)
      下一篇:apaas和集成平臺區(qū)別(從技術平臺到apaas)
      相關文章
      亚洲国产人成在线观看69网站 | 亚洲综合激情另类专区| 亚洲日韩乱码中文无码蜜桃| 亚洲Av永久无码精品三区在线| 亚洲日韩欧洲乱码AV夜夜摸| 亚洲午夜无码久久久久| 国产综合精品久久亚洲| 国产亚洲视频在线播放| 亚洲日本va在线视频观看| 亚洲VA综合VA国产产VA中| 一区二区三区亚洲视频| 国产成人久久精品亚洲小说| 国产成人亚洲综合a∨| 国产精品亚洲综合一区在线观看| 看亚洲a级一级毛片| 亚洲Aⅴ无码一区二区二三区软件 亚洲AⅤ视频一区二区三区 | 久久亚洲精品中文字幕无码| 亚洲AV无码成人网站久久精品大| 亚洲AV无码精品色午夜果冻不卡| 久久精品亚洲日本佐佐木明希| 亚洲第一福利视频| 亚洲色成人网一二三区| 亚洲六月丁香六月婷婷色伊人| 日韩亚洲产在线观看| 亚洲av午夜电影在线观看| 偷自拍亚洲视频在线观看99| 亚洲美女高清一区二区三区| 伊人久久大香线蕉亚洲五月天| 亚洲精品~无码抽插| 亚洲国产精品自在线一区二区| 亚洲精品乱码久久久久久下载 | 亚洲小说区图片区另类春色| 亚洲午夜久久久影院伊人| 亚洲国产精品无码成人片久久| 亚洲成在人天堂一区二区| 亚洲国产精品日韩在线观看| 亚洲中文无码亚洲人成影院| 国产精品亚洲lv粉色| 久久久久国产成人精品亚洲午夜| 亚洲国产第一站精品蜜芽| 中文字幕亚洲精品资源网|