Windows和Linux下通用的线程接口
对于多线程开发,Linux下有pthread线程库,使用起来比较方便,而Windows没有,对于涉及到多线程的跨平台代码开发,会带来不便。这里参考网络上的一些文章,整理了在Windows和Linux下通用的线程接口。经过测试,在Windows和Linux下均可正常使用。
Windows和Linux下对应的线程函数列表如下:
Windows和Linux线程通用接口如下:
#ifndef FBC_MESSY_TEST_THREAD_HPP_ #define FBC_MESSY_TEST_THREAD_HPP_ /* reference: http://locklessinc.com/articles/pthreads_on_windows/ http://locklessinc.com/downloads/winpthreads.h http://www.jmhartsoftware.com/Pthreads_Emulation.html https://sourceforge.net/p/log4c/log4c/ci/a4d3e19b3e55c1d5d66a5dc09a2603d9dcfcff52/tree/src/sd/sd_xplatform.h https://git.libav.org/?p=libav.git;a=blob;f=compat/w32pthreads.h;h=2fe2a5ab979ff676d1e7dba4a360306dde29a0f0;hb=HEAD https://github.com/krux/zookeeper-pkg/blob/master/src/c/src/winport.c https://my.oschina.net/mjRao/blog/359870 */ #ifdef _MSC_VER #include <windows.h> #include <sys/timeb.h> #include <process.h> typedef HANDLE pthread_mutex_t; typedef int pthread_condattr_t; typedef HANDLE pthread_t; typedef DWORD pthread_attr_t; #define pthread_create(thrp, attr, func, arg) \ (((*(thrp) = CreateThread(NULL, 0, \ (LPTHREAD_START_ROUTINE)(func), (arg), 0, NULL)) == NULL) ? -1 : 0) #define pthread_join(thr, statusp) \ ((WaitForSingleObject((thr), INFINITE) == WAIT_OBJECT_0) && \ ((statusp == NULL) ? 0 : \ (GetExitCodeThread((thr), (LPDWORD)(statusp)) ? 0 : -1))) #define PTHREAD_MUTEX_INITIALIZER {(void*)-1,-1,0,0,0,0} #define pthread_mutex_lock(pobject) WaitForSingleObject(*pobject,INFINITE) #define pthread_mutex_unlock(pobject) ReleaseMutex(*pobject) #define pthread_mutex_init(pobject,pattr) (*pobject=CreateMutex(NULL,FALSE,NULL)) #define pthread_mutex_destroy(pobject) CloseHandle(*pobject) /* Windows doesn't have this, so declare it ourselves. */ typedef struct timespec { /* long long in windows is the same as long in unix for 64bit */ long long tv_sec; long long tv_nsec; } timespec; typedef struct { int waiters_count_; // Number of waiting threads. CRITICAL_SECTION waiters_count_lock_; // Serialize access to <waiters_count_>. HANDLE sema_; // Semaphore used to queue up threads waiting for the condition to // become signaled. HANDLE waiters_done_; // An auto-reset event used by the broadcast/signal thread to wait // for all the waiting thread(s) to wake up and be released from the // semaphore. size_t was_broadcast_; // Keeps track of whether we were broadcasting or signaling. This // allows us to optimize the code if we're just signaling. } pthread_cond_t; static unsigned long long _pthread_time_in_ms(void) { struct __timeb64 tb; _ftime64(&tb); return tb.time * 1000 + tb.millitm; } static unsigned long long _pthread_time_in_ms_from_timespec(const struct timespec *ts) { unsigned long long t = ts->tv_sec * 1000; t += ts->tv_nsec / 1000000; return t; } static unsigned long long _pthread_rel_time_in_ms(const struct timespec *ts) { unsigned long long t1 = _pthread_time_in_ms_from_timespec(ts); unsigned long long t2 = _pthread_time_in_ms(); /* Prevent underflow */ if (t1 < t2) return 0; return t1 - t2; } static int pthread_cond_init(pthread_cond_t *cv, const pthread_condattr_t * ignore) { cv->waiters_count_ = 0; cv->was_broadcast_ = 0; cv->sema_ = CreateSemaphore(NULL, // no security 0, // initially 0 0x7fffffff, // max count NULL); // unnamed if (cv->sema_ == NULL) return GetLastError(); InitializeCriticalSection(&cv->waiters_count_lock_); cv->waiters_done_ = CreateEvent(NULL, // no security FALSE, // auto-reset FALSE, // non-signaled initially NULL); // unnamed return (cv->waiters_done_ == NULL) ? GetLastError() : 0; } static int pthread_cond_destroy(pthread_cond_t *cond) { CloseHandle(cond->sema_); DeleteCriticalSection(&cond->waiters_count_lock_); return (CloseHandle(cond->waiters_done_) == 0) ? GetLastError() : 0; } static int pthread_cond_signal(pthread_cond_t *cv) { int have_waiters; EnterCriticalSection(&(cv->waiters_count_lock_)); have_waiters = cv->waiters_count_ > 0; LeaveCriticalSection(&cv->waiters_count_lock_); // If there aren't any waiters, then this is a no-op. if (have_waiters){ return (ReleaseSemaphore(cv->sema_, 1, 0) == 0) ? GetLastError() : 0; } else return 0; } static int pthread_cond_broadcast(pthread_cond_t *cv) { // This is needed to ensure that <waiters_count_> and <was_broadcast_> are // consistent relative to each other. int have_waiters = 0; EnterCriticalSection(&cv->waiters_count_lock_); if (cv->waiters_count_ > 0) { // We are broadcasting, even if there is just one waiter... // Record that we are broadcasting, which helps optimize // <pthread_cond_wait> for the non-broadcast case. cv->was_broadcast_ = 1; have_waiters = 1; } if (have_waiters) { // Wake up all the waiters atomically. ReleaseSemaphore(cv->sema_, cv->waiters_count_, 0); LeaveCriticalSection(&cv->waiters_count_lock_); // Wait for all the awakened threads to acquire the counting // semaphore. WaitForSingleObject(cv->waiters_done_, INFINITE); // This assignment is okay, even without the <waiters_count_lock_> held // because no other waiter threads can wake up to access it. cv->was_broadcast_ = 0; } else LeaveCriticalSection(&cv->waiters_count_lock_); return 0; } static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *external_mutex) { int last_waiter; // Avoid race conditions. EnterCriticalSection(&cv->waiters_count_lock_); cv->waiters_count_++; LeaveCriticalSection(&cv->waiters_count_lock_); // This call atomically releases the mutex and waits on the // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast> // are called by another thread. SignalObjectAndWait(*external_mutex, cv->sema_, INFINITE, FALSE); // Reacquire lock to avoid race conditions. EnterCriticalSection(&cv->waiters_count_lock_); // We're no longer waiting... cv->waiters_count_--; // Check to see if we're the last waiter after <pthread_cond_broadcast>. last_waiter = cv->was_broadcast_ && cv->waiters_count_ == 0; LeaveCriticalSection(&cv->waiters_count_lock_); // If we're the last waiter thread during this particular broadcast // then let all the other threads proceed. if (last_waiter) // This call atomically signals the <waiters_done_> event and waits until // it can acquire the <external_mutex>. This is required to ensure fairness. SignalObjectAndWait(cv->waiters_done_, *external_mutex, INFINITE, FALSE); else // Always regain the external mutex since that's the guarantee we // give to our callers. WaitForSingleObject(*external_mutex, INFINITE); return 0; } #else // linux #include <pthread.h> #endif // _MSC_VER #endif // FBC_MESSY_TEST_THREAD_HPP_
测试代码如下:
#include "test_thread.hpp" #include <iostream> #include "thread.hpp" // test code reference: http://blog.csdn.net/fengbingchun/article/details/48579725 void* run1(void* para) { std::cout << "start new thread!" << std::endl; //sleep(5);//suspend 5 s,在正式的代码中,一般不要用sleep函数 int* iptr = (int*)((void**)para)[0]; float* fptr = (float*)((void**)para)[1]; char* str = (char*)((void**)para)[2]; std::cout << *iptr << " " << *fptr << " " << str << std::endl; std::cout << "end new thread!" << std::endl; return ((void *)0); } int test_create_thread() { pthread_t pid;//thread handle int ival = 1; float fval = 10.0f; char buf[] = "func"; void* para[3] = { &ival, &fval, buf }; pthread_create(&pid, NULL, run1, para); // 新线程创建之后主线程如何运行----主线程按顺序继续执行下一行程序 std::cout << "main thread!" << std::endl; // 新线程结束时如何处理----新线程先停止,然后作为其清理过程的一部分,等待与另一个线程合并或“连接” pthread_join(pid, NULL); return 0; } ///////////////////////////////////////////////////////// pthread_t tid[2]; int counter = 0; pthread_mutex_t lock; void* run2(void* arg) { pthread_mutex_lock(&lock); unsigned long i = 0; counter += 1; std::cout << "Job " << counter << " started!" << std::endl; for (i = 0; i<(0xFFFFFFFF); i++); std::cout << "Job " << counter << " finished!" << std::endl; pthread_mutex_unlock(&lock); return NULL; } int test_thread_mutex() { int i = 0, err = -1; pthread_mutex_init(&lock, NULL); while (i < 2) { pthread_create(&(tid[i]), NULL, &run2, NULL); i++; } pthread_join(tid[0], NULL); pthread_join(tid[1], NULL); pthread_mutex_destroy(&lock); return 0; } ///////////////////////////////////////////////// pthread_mutex_t count_lock1; pthread_cond_t count_nonzero1; unsigned count1 = 0; void* decrement_count1(void* arg) { pthread_mutex_lock(&count_lock1); std::cout << "decrement_count get count_lock" << std::endl; while (count1 == 0) { std::cout << "decrement_count count == 0" << std::endl; std::cout << "decrement_count before cond_wait" << std::endl; pthread_cond_wait(&count_nonzero1, &count_lock1); std::cout << "decrement_count after cond_wait" << std::endl; } count1 = count1 + 1; pthread_mutex_unlock(&count_lock1); return NULL; } void* increment_count1(void* arg) { pthread_mutex_lock(&count_lock1); std::cout << "increment_count get count_lock" << std::endl; if (count1 == 0) { std::cout << "increment_count before cond_signal" << std::endl; pthread_cond_signal(&count_nonzero1); std::cout << "increment_count after cond_signal" << std::endl; } count1 = count1 + 1; pthread_mutex_unlock(&count_lock1); return NULL; } int test_thread_cond1() { pthread_t tid1, tid2; pthread_mutex_init(&count_lock1, NULL); pthread_cond_init(&count_nonzero1, NULL); pthread_create(&tid1, NULL, decrement_count1, NULL); Sleep(2000); // == linux sleep(2) pthread_create(&tid2, NULL, increment_count1, NULL); Sleep(2000); pthread_join(tid1, NULL); pthread_join(tid2, NULL); pthread_mutex_destroy(&count_lock1); pthread_cond_destroy(&count_nonzero1); return 0; } //////////////////////////////////////////////////////////// pthread_mutex_t counter_lock2; pthread_cond_t counter_nonzero2; int counter2 = 0; void* decrement_counter2(void* argv) { std::cout << "counter(decrement): " << counter2 << std::endl; pthread_mutex_lock(&counter_lock2); while (counter2 == 0) pthread_cond_wait(&counter_nonzero2, &counter_lock2); //进入阻塞(wait),等待激活(signal) std::cout << "counter--(decrement, before): " << counter2 << std::endl; counter2--; //等待signal激活后再执行 std::cout << "counter--(decrement, after): " << counter2 << std::endl; pthread_mutex_unlock(&counter_lock2); return NULL; } void* increment_counter2(void* argv) { std::cout << "counter(increment): " << counter2 << std::endl; pthread_mutex_lock(&counter_lock2); if (counter2 == 0) pthread_cond_signal(&counter_nonzero2); //激活(signal)阻塞(wait)的线程(先执行完signal线程,然后再执行wait线程) std::cout << "counter++(increment, before): " << counter2 << std::endl; counter2++; std::cout << "counter++(increment, after): " << counter2 << std::endl; pthread_mutex_unlock(&counter_lock2); return NULL; } int test_thread_cond2() { std::cout << "counter: " << counter2 << std::endl; pthread_mutex_init(&counter_lock2, NULL); pthread_cond_init(&counter_nonzero2, NULL); pthread_t thd1, thd2; pthread_create(&thd1, NULL, decrement_counter2, NULL); pthread_create(&thd2, NULL, increment_counter2, NULL); int counter2 = 0; while (counter2 != 10) { std::cout << "counter(main): " << counter2 << std::endl; Sleep(1); counter2++; } pthread_join(thd1, NULL); pthread_join(thd2, NULL); pthread_mutex_destroy(&counter_lock2); pthread_cond_destroy(&counter_nonzero2); return 0; } /////////////////////////////////////////////////// pthread_mutex_t counter_lock3_1, counter_lock3_2; pthread_cond_t counter_nonzero3_1, counter_nonzero3_2; int counter3 = 0; void* decrement_increment_counter3(void* argv) { std::cout << "start counter: " << counter3 << std::endl; pthread_mutex_lock(&counter_lock3_1); std::cout << "counter(decrement): " << counter3 << std::endl; while (counter3 == 1) pthread_cond_wait(&counter_nonzero3_1, &counter_lock3_1); //进入阻塞(wait),等待激活(signal) std::cout << "counter--(decrement, before): " << counter3 << std::endl; counter3--; //等待signal激活后再执行 std::cout << "counter--(decrement, after): " << counter3 << std::endl; pthread_mutex_unlock(&counter_lock3_1); pthread_mutex_lock(&counter_lock3_2); std::cout << "counter(increment): " << counter3 << std::endl; if (counter3 == 0) pthread_cond_signal(&counter_nonzero3_2); //激活(signal)阻塞(wait)的线程(先执行完signal线程,然后再执行wait线程) std::cout << "counter++(increment, before): " << counter3 << std::endl; counter3++; std::cout << "counter++(increment, after): " << counter3 << std::endl; pthread_mutex_unlock(&counter_lock3_2); return NULL; } int test_thread_cond3() { std::cout << "counter: " << counter3 << std::endl; pthread_mutex_init(&counter_lock3_1, NULL); pthread_mutex_init(&counter_lock3_2, NULL); pthread_cond_init(&counter_nonzero3_1, NULL); pthread_cond_init(&counter_nonzero3_2, NULL); pthread_t thd; pthread_create(&thd, NULL, decrement_increment_counter3, NULL); counter3 = 0; while (counter3 != 10) { std::cout << "counter(main): " << counter3 << std::endl; Sleep(1000); counter3++; } pthread_join(thd, NULL); pthread_mutex_destroy(&counter_lock3_1); pthread_mutex_destroy(&counter_lock3_2); pthread_cond_destroy(&counter_nonzero3_1); pthread_cond_destroy(&counter_nonzero3_2); return 0; }
GitHub:https://github.com/fengbingchun/Messy_Test
Windows和Linux下通用的线程接口的更多相关文章
- 【java】java下载文件中换行符 在windows和linux下通用的
请使用: public static final String FILE_CONTENT_SPLIT_MARK = "\r\n"; 注意 不是"\n\r",顺序 ...
- Windows与Linux下文件操作监控的实现
一.需求分析: 随着渲染业务的不断进行,数据传输渐渐成为影响业务时间最大的因素.究其原因就是因为数据传输耗费较长的时间.于是,依托于渲染业务的网盘开发逐渐成为迫切需要解决的需求.该网盘的实现和当前市场 ...
- 怎样在Windows和Linux下写相同的代码
目前,Linux在国内受到了越来越多的业内人士和用户的青睐.相信在不久的将来,在国内为Linux开发 的应用软件将会有很大的增加(这不,金山正在招兵买马移植WPS呢).由于未来将会是Windows和L ...
- php windows与linux下的路径区别
php windows与linux下的路径区别windows用的是"\",linux用的是"/"这一点要特别清楚,, ps:在PHP windows也可以用/表 ...
- 不错的linux下通用的java程序启动脚本
不错的linux下通用的java程序启动脚本(转载) 虽然写起动shell的频率非常不高...但是每次要写都要对付一大堆的jar文件路径,新加jar包也必须要修改起动shell. 在网上找到一个挺好的 ...
- Windows 和 Linux 下 禁止ping的方法
Windows 和Linux 下 禁止ping的方法 目的: 禁止网络上的其他主机或服务器ping自己的服务器 运行环境: Windows 03.08 linux 方法: Windows 03下: ...
- socket在windows下和linux下的区别
原文:socket在windows下和linux下的区别 1)头文件 windows下winsock.h/winsock2.h linux下sys/socket.h 错误处理:errno.h 2 ...
- windows和linux下关闭Tomcat进程
windows和linux下解决Tomcat进程 windows下启动Tomcat报错,8080端口号被占用,报错信息如下 两种解决方法,一种是关闭了这个端口号,另外一种是修改Tomcat下的serv ...
- HDP2.0.6+hadoop2.2.0+eclipse(windows和linux下)调试环境搭建
花了好几天,搭建好windows和linux下连接HDP集群的调试环境,在此记录一下 hadoop2.2.0的版本比hadoop0.x和hadoop1.x结构变化很大,没有eclipse-hadoop ...
随机推荐
- Oracle EBS 导入日记账报错
EM29/EM01 ED01
- NSOperation的使用细节 [3]
NSOperation的使用细节 [3] 这一节我们来写自定义concurrent的operation,自定义concurrent的operation稍微有点复杂,需要按照某些既定的步骤编写才可以完成 ...
- 使用截图工具FastStone Capture
使用截图工具FastStone Capture -谨以此教程献给某位上进的测试人员- FastStone Capture是本人用过的windows平台上最好用的截图工具,界面简洁,功能强大,还支持屏幕 ...
- Windows:删除图标缓存
适用于桌面快捷方式图标丢失或图标变成白色的情况,批处理代码如下: rem 关闭explorer.exe taskkill /f /im explorer.exe attrib -h -i %userp ...
- springsource-tool-suite插件的在线安装
1 首先,确定你现在使用的eclipse属于哪个版本? 查看自己的eclipse平台的版本(我的eclipse平台版本是4.3) 2 根据eclipse版本,选择插件的版本 官网:ht ...
- linux之安装nali本地解析IP归属
参考博文:http://www.dwhd.org/20150802_014526.html 1.安装nali wget http://www.dwhd.org/wp-content/uploads/2 ...
- [微信小程序直播平台开发]___(二)Nginx+rtmp在Windows中的搭建
1.一个可以忽略的前言 Nginx (engine x) 是一个高性能的HTTP和反向代理服务,也是一个IMAP/POP3/SMTP服务.Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Ramble ...
- 【LGP4886 】快递员
题目 好秒啊,真是一道神仙的点分治 于是我们来一个暴力的\(O(nlog^2n)\)的暴力统计吧 考虑计算每一个点作为快递中心时的答案 我们考虑在这个点成为分治重心时计算这个贡献 把这个贡献分成两部分 ...
- 【openjudge】【字符串】P6374文字排版
[描述] 给一段英文短文,单词之间以空格分隔(每个单词包括其前后紧邻的标点符号).请将短文重新排版,要求如下: 每行不超过80个字符:每个单词居于同一行上:在同一行的单词之间以一个空格分隔:行首和行尾 ...
- CF585D Lizard Era: Beginning
嘟嘟嘟 题面我是不会咕的(没有真香):有\(n(n \leqslant 25)\)个任务和三个人,每次任务给出每个人能得到的值,每次任务选两个人,使\(n\)个任务结束后三个人得到的值是一样的,且尽量 ...