有些文不对题了;
最近搞线程池并发过程中突然想起来用 原子类型 来替换一些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{ 仍回队列 / 某个容器里 }