有些文不對題了;
最近搞線程池併發過程中突然想起來用 原子類型 來替換一些mutex, rwlock, cond這些東西;
比如一個reactor 的epoll+線程池[ 例如4個 ], 在發送數據時爲了保證tcp socket的數據順序,
必須加鎖處理 [ 這種模型不容易控制, 實際工程中別用, 對於 socket 還是有一個線程來處理最簡單也避免競爭問題].
然後我發現了個好東西;
下面的測試代碼用 atomic_flag 來替換mutex;
一共沒幾行代碼, 但基本說明了問題.
如果你做併發send(socket,... ) 看懂了下面的代碼, 也就知道該怎麼做了
using namespace std;
#include <atomic>
atomic_flag lk = ATOMIC_FLAG_INIT; //初始化,一開始是false
int g = 0; //全局變量, ++用的
unsigned int __stdcall th_func(void *arg){
bool ret = 0;
int c = 0;
while(1){
/*
test_and_set 的作用: 原子的設置爲 true.
只有當你設置成功 爲 true時 ,才返回 false ,
意思是隻有當 lk 爲 false 時, 你才能設置成功,
否則返回之前的值 : true;
*/
//原子的設置 true, 50個線程只有一個線程能設置爲true,返回false,其他都返回true
/*
可設置 std::memery_order_relaxed
不需要保證內存順序, 這裏只要保證 原子性就ok , 因此可隨意他的內存順序.
*/
ret = lk.test_and_set(); //就這一行代碼 ,看懂了就全懂了
if(!ret){
// 50個線程中只有唯一一個線程在原子的設置成功後進入
//這裏相當於進入 mutex了
++g;
++c;
// 把lk原子的設置爲 false , 相當於 unlock
lk.clear();
if(c == 100000)
break;
}
}
return 0;
}
int main(int argc, char* argv[])
{
static const int n = 50;
HANDLE * arr = new HANDLE[n];
// 起線程
for(int i = 0; i < n; ++i){
arr[i] = (HANDLE)_beginthreadex(0,0,th_func,0,0,0);
}
WaitForMultipleObjects(n,arr,TRUE,INFINITE);
cout << "main done :" << g << endl;
return 0;
}
接下來的問題就容易解決了,
在線程池中:
ret = lk.test_and_set();
if(!ret){
send / write
}
else{
仍回隊列 / 某個容器裏
}