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 系统仅存在英文的环境
系统管理员 应用服务器 adadmin 编译
- Vue2学习笔记:v-show指令
v-show指令:v-show="true/false" 控制元素显示/隐藏 1.使用 <!DOCTYPE html> <html> <head> ...
- Mysql压缩解决方案
提到mysql压缩相关的内容,我们能想到的可能是如下几种和压缩相关的场景: 1.客户端和服务器之间传输的数据量太大,需要进行压缩,节约带宽 2.mysql某个列的数据量大,只针对某个列的数据压缩 3. ...
- ARC下的block导致的循环引用问题解析
ARC下的block导致的循环引用问题解析 更详细细节请参考 http://blog.sina.com.cn/s/blog_8c87ba3b0101m599.html ARC下,copy到堆上的blo ...
- win10想说爱你不容易——安装.net3.5也是一个坑(已有完美解决方法)
最终完美解决方法:经过多次波折,终于找到无法正常安装.net3.5的原因了,是因为已删除的用户还有注册表残留导致的,而且这个问题还会影响一个win10更新的安装,导致每天更新失败,撤销更新... 详见 ...
- September 04th 2017 Week 36th Monday
Try not to become a man of success but rather try to become a man of value. 不要努力去做一个成功的人,而要努力去做一个有价值 ...
- 题解 P1894 【[USACO4.2]完美的牛栏The Perfect Stall】
题面 农夫约翰上个星期刚刚建好了他的新牛棚,他使用了最新的挤奶技术.不幸的是,由于工程问题,每个牛栏都不一样.第一个星期,农夫约翰随便地让奶牛们进入牛栏,但是问题很快地显露出来:每头奶牛都只愿意在她们 ...
- C语言利用 void 类型指针实现面向对象类概念与抽象。
不使用C++时,很多C语言新手可能认为C语言缺乏了面向对象和抽象性,事实上,C语言通过某种组合方式,可以间接性的实现面对对象和抽象. 不过多态和继承这种实现,就有点小麻烦,但是依然可以实现. 核心: ...
- 1208. [HNOI2004]宠物收养场【平衡树-splay】
Description 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特 ...
- [USACO19FEB]Moorio Kart
题目 我们的神仙教练在考试里放了这道题,当时我非常惊讶啊 背包是\(O(n^3)\)的吧明明是带根号的好吧,那既然要优化的话 NTT!什么时候我们教练会在考试里放多项式了 模数\(1e9+7\)? 任 ...