示例程式如下
#include
#include
#include
#define thread_count 10
void
*thread_callback
(void
* arg)
}int
main()
;int count =0;
for(
int i=
0; i< thread_count; i++
)for
(int i =
0; i <
100; i++
)return0;
}
編譯命令
gcc lock.c -pthread -o lock
執行結果:
對於上述程式,無法加到100000,從彙編指令簡單分析,count++ 的彙編指令如下
mov [count], eax
inc eax;
mov eax, [count]
在多執行緒切換時,在執行緒1
執行第一條指令後,切換至執行緒 2
,此時執行緒2自增1返回執行緒1
,程序上下文進行切換,使得原來的eax
值不變,所以 count 在兩個執行緒執行結束,僅自增了一次。如下圖所示
解決方案:使用互斥鎖對臨界資源進行訪問保護。互斥鎖可以將三條彙編指令看做一條指令,必須全部執行完,才能進行下一次執行,對臨界資源加互斥鎖進行訪問。使用互斥鎖的4個介面:
定義互斥鎖
pthread_mutex_t mutex;
初始化互斥鎖
pthread_mutex_init
(&mutex,
null
);
對臨界資源加鎖
pthread_mutex_lock
(&mutex)
;
對臨界資源解鎖
pthread_mutex_unlock
(&mutex)
;
程式**如下
#include
#include
#include
#define thread_count 10
// 1. 定義互斥鎖
pthread _mutex_t mutex;
void
*thread_callback
(void
* arg)
}int
main()
;// 2. 初始化互斥鎖
pthread_mutex_init
(&mutex,
null);
int count =0;
for(
int i=
0; i< thread_count; i++
)for
(int i =
0; i <
100; i++
)return0;
}
再次編譯執行,可以累加到100000,結果如下
自旋鎖的定義:當乙個執行緒嘗試去獲取某一把鎖的時候,如果這個鎖此時已經被別人獲取(占用),那麼此執行緒就無法獲取到這把鎖,該執行緒將會等待,間隔一段時間後會再次嘗試獲取。這種採用迴圈加鎖 -> 等待的機制被稱為自旋鎖(spinlock)。
自旋鎖的使用方式與互斥鎖相同,4個介面如下:
定義自旋鎖
pthread_spinlock_t spinlock;
初始化自旋鎖
pthread_spin_init
(&spinlock, pthread_process_shared)
;
對臨界資源加鎖
pthread_spin_lock
(&spinlock)
;
對臨界資源解鎖
pthread_spin_unlock
(&spinlock)
;
程式**如下
#include
#include
#include
#define thread_count 10
// 1. 定義自旋鎖
pthread_spinlock_t spinlock;
void
*thread_callback
(void
* arg)
}int
main()
;// 2. 初始化自旋鎖
pthread_spin_init
(&spinlock, pthread_process_shared)
;int count =0;
for(
int i=
0; i< thread_count; i++
)for
(int i =
0; i <
100; i++
)return0;
}
編譯執行結果如下
自旋鎖與互斥鎖區別?使用場景有何不同?使用彙編指令,將自增操作寫為一條指令,成為原子操作。對於臨界資源的保護,一種是沒有獲取到鎖的執行緒就一直迴圈等待判斷該資源是否已經釋放鎖,這種鎖叫做自旋鎖,它不用將執行緒阻塞起來(non-blocking);還有一種處理方式就是把自己阻塞起來,等待重新排程請求,這種叫做互斥鎖。互斥鎖需要程序切換,而自旋鎖的實現則是等待。
__asm__ volatile
("lock; xaddl %2, %1;"
:"=a"
(old)
:"m"
(*value)
,"a"
(add)
:"cc"
,"memory"
);
**如下
#include
#include
#include
#define thread_count 10
intinc
(int
* value,
int add)
void
*thread_callback
(void
* arg)
}int
main()
;int count =0;
for(
int i=
0; i< thread_count; i++
)for
(int i =
0; i <
100; i++
)return0;
}
執行結果如下
看完你就明白的鎖系列之自旋鎖
併發程式設計筆記(一) 多執行緒
一 我們為什麼要使用多執行緒 首先要了解一點,我們跑程式最耗時的是io讀寫,所以會出現來了很多請求,卻要等待第乙個請求io結束才能繼續接受下乙個請求,非常影響效率 另外,單執行緒的請求處理是線性的,前端發起請求需要等待後台所有的都處理結束前端才有響應,非常影響體驗。針對這兩點,多執行緒的優勢在於 1...
多執行緒併發程式設計(一)
在解決多執行緒併發帶來的效能問題時,我們首先想到的一定是執行緒池。但配置執行緒池的幾個關鍵引數時,必須基於生產環境系統資源以及線上流量,設定合理的引數值。執行緒數量設定太小,會導致程式不能充分地利用系統資源 執行緒數量設定太大,又可能帶來資源的過度競爭,導致上下文切換造成額外的系統效能開銷。尤其執行...
Python多執行緒(一) 多執行緒的建立
在python3中,多執行緒主要使用threading模組 首先,來看乙個單任務模式的例子 import datetime,time defeat hotpot food for i in range 2 print datetime.datetime.now strftime x eat str ...