定制網(wǎng)站設(shè)計(jì)租空間開網(wǎng)站
鶴壁市浩天電氣有限公司
2026/01/24 10:41:17
定制網(wǎng)站設(shè)計(jì),租空間開網(wǎng)站,遼寧省城鄉(xiāng)和建設(shè)廳網(wǎng)站,嗶哩嗶哩網(wǎng)頁(yè)版怎么回到舊版目錄
一、臨界資源與線程安全問題
二、互斥#xff1a;讓臨界區(qū) “獨(dú)占” 執(zhí)行
1.互斥鎖的原理
2.互斥鎖的使用步驟#xff08;pthread 庫(kù)#xff09;
2.1 定義互斥鎖
2.2 初始化互斥鎖
2.3 加鎖#xff08;進(jìn)入臨界區(qū)#xff09;
2.4 解鎖#xff08;離開臨界區(qū)…目錄一、臨界資源與線程安全問題二、互斥讓臨界區(qū) “獨(dú)占” 執(zhí)行1.互斥鎖的原理2.互斥鎖的使用步驟pthread 庫(kù)2.1 定義互斥鎖2.2 初始化互斥鎖2.3 加鎖進(jìn)入臨界區(qū)2.4 解鎖離開臨界區(qū)2.5 銷毀互斥鎖3.互斥鎖實(shí)戰(zhàn)示例三、同步讓線程 “按順序” 執(zhí)行1. 同步與互斥的關(guān)系2.信號(hào)量的原理3.信號(hào)量的使用步驟3.1 定義信號(hào)量3.2 初始化信號(hào)量3.3 信號(hào)量的 PV 操作3.4 銷毀信號(hào)量4.信號(hào)量同步實(shí)戰(zhàn)示例四、死鎖一、臨界資源與線程安全問題臨界資源在線程間會(huì)被讀寫操作的資源比如全局變量、文件、硬件設(shè)備。線程安全問題多個(gè)線程 “穿插執(zhí)行” 臨界資源的操作時(shí)會(huì)破壞數(shù)據(jù)一致性。舉個(gè)例子A看似是一行代碼但編譯后會(huì)分成 3 步讀 A→A1→寫回 A。如果線程 1 執(zhí)行到 “讀 A” 后被切換到線程 2線程 2 也執(zhí)行A最終 A 的值會(huì)比預(yù)期小 —— 這就是數(shù)據(jù)競(jìng)爭(zhēng)。二、互斥讓臨界區(qū) “獨(dú)占” 執(zhí)行互斥的核心是排他性訪問同一時(shí)刻只有一個(gè)線程能操作臨界資源。1.互斥鎖的原理通過 “鎖” 來保護(hù)臨界區(qū)代碼操作臨界資源的代碼線程要執(zhí)行臨界區(qū)必須先 “加鎖”鎖被占用時(shí)其他線程會(huì)阻塞等待線程執(zhí)行完臨界區(qū)必須 “解鎖”讓其他線程可以競(jìng)爭(zhēng)鎖。th1、th2是并發(fā)運(yùn)行的兩個(gè)線程。也就是代碼在運(yùn)行時(shí)th1與th2是穿插進(jìn)行的。2.互斥鎖的使用步驟pthread 庫(kù)Linux 下用 pthread_mutex_t 實(shí)現(xiàn)互斥鎖步驟是定義→初始化→加鎖→解鎖→銷毀。2.1 定義互斥鎖#include pthread.h // 定義全局/共享的互斥鎖 pthread_mutex_t mutex;2.2 初始化互斥鎖// 函數(shù)原型 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); // 示例 pthread_mutex_init(mutex, NULL);功能將已經(jīng)定義好的互斥鎖初始化。參數(shù)mutex 是要初始化的鎖attr 傳NULL表示用默認(rèn)屬性。返回值成功返回 0失敗返回非 0。2.3 加鎖進(jìn)入臨界區(qū)// 函數(shù)原型 int pthread_mutex_lock(pthread_mutex_t *mutex);功能用指定的互斥鎖開始加鎖代碼成功則進(jìn)入臨界區(qū)失敗則阻塞等待。注意加鎖后的代碼是原子操作線程調(diào)度不會(huì)打斷這段代碼。2.4 解鎖離開臨界區(qū)// 函數(shù)原型 int pthread_mutex_unlock(pthread_mutex_t *mutex);功能將指定的互斥鎖解鎖讓其他線程可以競(jìng)爭(zhēng)。解鎖之后代碼不再排他訪問。注意加鎖和解鎖必須成對(duì)出現(xiàn)且要在同一個(gè)線程中執(zhí)行。2.5 銷毀互斥鎖// 函數(shù)原型 int pthread_mutex_destroy(pthread_mutex_t *mutex);功能釋放互斥鎖的資源鎖不再使用時(shí)調(diào)用。3.互斥鎖實(shí)戰(zhàn)示例比如兩個(gè)線程同時(shí)對(duì)全局變量 A 做 操作用互斥鎖保證線程安全#include pthread.h #include stdio.h int A 0; pthread_mutex_t mutex; // 線程函數(shù) void* th(void* arg) { int i 5000; while (i--) { // 加鎖進(jìn)入臨界區(qū) pthread_mutex_lock(mutex); int tmp A; printf(A is %d
, tmp 1); // 循環(huán)輸出到 A is 10000 A tmp 1; // 解鎖離開臨界區(qū) pthread_mutex_unlock(mutex); } return NULL; } int main(int argc, char** argv) { pthread_t tid1, tid2; // 初始化互斥鎖 pthread_mutex_init(mutex, NULL); pthread_create(tid1, NULL, th, NULL); pthread_create(tid2, NULL, th, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); // 銷毀互斥鎖 pthread_mutex_destroy(mutex); return 0; }三、同步讓線程 “按順序” 執(zhí)行互斥解決了 “資源獨(dú)占”但沒解決 “執(zhí)行順序”。同步是讓線程按預(yù)先約定的順序執(zhí)行比如 “線程 1 輸出 Hello 后線程 2 再輸出 World”。1. 同步與互斥的關(guān)系同步是互斥的 “特例”同步不僅要排他訪問還要控制執(zhí)行順序。實(shí)現(xiàn)同步的工具信號(hào)量可以理解為 “帶計(jì)數(shù)的鎖”?;コ怄i加鎖和解鎖是同一個(gè)線程臨界區(qū)代碼短小精悍避免休眠、大耗時(shí)的操作信號(hào)量th1 釋放 th2th2 釋放 th1。由線程交叉釋放??梢杂羞m當(dāng)休眠、小的耗時(shí)操作2.信號(hào)量的原理信號(hào)量是一個(gè)整數(shù) sem通過 P 操作申請(qǐng)資源和 V 操作釋放資源實(shí)現(xiàn)同步P 操作sem--若 sem0 則線程阻塞V 操作sem若 sem0 則喚醒一個(gè)阻塞的線程。注Linux 下用 sem_t 實(shí)現(xiàn)信號(hào)量3.信號(hào)量的使用步驟步驟是定義→初始化→PV 操作→銷毀。3.1 定義信號(hào)量#include semaphore.h sem_t sem;3.2 初始化信號(hào)量// 函數(shù)原型 int sem_init(sem_t *sem, int pshared, unsigned int value);參數(shù)sem要初始化的信號(hào)量pshared0表示線程間共享非 0 表示進(jìn)程間共享value信號(hào)量初始值比如 0 表示 “無資源”1 表示 “有 1 個(gè)資源”。返回值成功返回 0失敗返回 -1。3.3 信號(hào)量的 PV 操作P 操作申請(qǐng)資源對(duì)應(yīng)sem_wait()int sem_wait(sem_t *sem);功能判斷當(dāng)前 sem 信號(hào)量是否有資源可用。如果 sem 有資源 (1)則申請(qǐng)?jiān)撡Y源程序繼續(xù)運(yùn)行如果 sem 沒有資源 (0)則線程阻塞等待一旦有資源則自動(dòng)申請(qǐng)資源并繼續(xù)運(yùn)行程序。V 操作釋放資源對(duì)應(yīng)sem_post()int sem_post(sem_t *sem);功能函數(shù)可以將指定的 sem 信號(hào)量資源釋放并默認(rèn)執(zhí)行 sem sem1。線程在該函數(shù)上不會(huì)阻塞。3.4 銷毀信號(hào)量int sem_destroy(sem_t *sem);功能使用完畢將指定的信號(hào)量銷毀。4.信號(hào)量同步實(shí)戰(zhàn)示例#include pthread.h #include semaphore.h #include stdio.h #include unistd.h sem_t sem_H, sem_W; // 線程1輸出Hello void *th1(void *arg) { int i 10; while (i--) { sem_wait(sem_H); printf(hello ); fflush(stdout); sem_post(sem_W); } return NULL; } // 線程2輸出World void *th2(void *arg) { int i 10; while (i--) { sem_wait(sem_W); printf(world
); sleep(1); sem_post(sem_H); } return NULL; } int main(int argc, char **argv) { pthread_t tid1, tid2; // 初始化信號(hào)量sem_H1線程1可以直接執(zhí)行sem_W0線程2等待 sem_init(sem_H, 0, 1); sem_init(sem_W, 0, 0); pthread_create(tid1, NULL, th1, NULL); pthread_create(tid2, NULL, th2, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); sem_destroy(sem_H); sem_destroy(sem_W); return 0; }四、死鎖由于鎖資源安排的不合理鎖資源的申請(qǐng)和釋放邏輯不對(duì)導(dǎo)致進(jìn)程、線程無法正常繼續(xù)執(zhí)行推進(jìn)的現(xiàn)象。產(chǎn)生死鎖的四個(gè)必要條件互斥條件一個(gè)資源每次只能被一個(gè)進(jìn)程使用。請(qǐng)求與保持條件一個(gè)進(jìn)程因請(qǐng)求資源而阻塞時(shí)對(duì)已獲得的資源保持不放。不剝奪條件進(jìn)程已獲得的資源在末使用完之前不能強(qiáng)行剝奪。循環(huán)等待條件若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系。破壞任意一個(gè)就能避免死鎖比如按固定順序申請(qǐng)資源。