使用pthread下的mutex与cond_var模拟windows下的event几个接口
两个版本的链接:
https://github.com/neosmart/pevents
https://github.com/moya-lang/Event
第一个版本能够模拟等待多个事件中的一个触发,而后者仅最多支持一个事件
但第一个版本在UnlockedWaitForEvent执行后,是需要增加一个判断的,否则会不正确
代码:
#if 0 //#define PULSE
//#define WFMO #include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <sys/time.h> #ifdef WFMO
#include <algorithm>
#include <deque>
#endif struct SyncObjectPosix_event_st; // Function declarations
void* CreateEvent(void* lpEventAttributes = nullptr, bool manualReset = false, bool initialState = false, void* lpName = nullptr);
int DestroyEvent(void* event);
//int WaitForEvent(void* event, uint64_t milliseconds = -1);
int WaitForSingleObject(void* event, uint64_t milliseconds = -);
int SetEvent(void* event);
int ResetEvent(void* event);
#ifdef WFMO
int WaitForMultipleObjects(int nCount,const void* *lpHandles, bool bWaitAll, uint64_t milliseconds); int WaitForMultipleEvents(void* *events, int count, bool waitAll,
uint64_t milliseconds);
int WaitForMultipleEvents(void* *events, int count, bool waitAll,
uint64_t milliseconds, int &index);
#endif
#ifdef PULSE
int PulseEvent(void* event);
#endif #ifdef WFMO
// Each call to WaitForMultipleObjects initializes a neosmart_wfmo_t object which tracks
// the progress of the caller's multi-object wait and dispatches responses accordingly.
// One neosmart_wfmo_t struct is shared for all events in a single WFMO call
typedef struct SyncObjectPosix_wfmo_st {
pthread_mutex_t Mutex;
pthread_cond_t CVariable;
int RefCount;
union {
int FiredEvent; // WFSO
int EventsLeft; // WFMO
} Status;
bool WaitAll;
bool StillWaiting; void Destroy() {
pthread_mutex_destroy(&Mutex);
pthread_cond_destroy(&CVariable);
}
}SyncObjectPosix_wfmo_st;
//typedef SyncObjectPosix_wfmo_t_ *SyncObjectPosix_wfmo_t; // A neosmart_wfmo_info_t object is registered with each event waited on in a WFMO
// This reference to neosmart_wfmo_t_ is how the event knows whom to notify when triggered
typedef struct SyncObjectPosix_wfmo_info_st {
SyncObjectPosix_wfmo_st* Waiter;
int WaitIndex;
}SyncObjectPosix_wfmo_info_st;
//typedef SyncObjectPosix_wfmo_info_t_ *nSyncObjectPosix_wfmo_info_t;
#endif // WFMO // The basic event structure, passed to the caller as an opaque pointer when creating events
typedef struct SyncObjectPosix_event_st {
pthread_cond_t CVariable;
pthread_mutex_t Mutex;
bool AutoReset;
bool State;
#ifdef WFMO
std::deque<SyncObjectPosix_wfmo_info_st> RegisteredWaits;
#endif
}SyncObjectPosix_event_st; #ifdef WFMO
bool RemoveExpiredWaitHelper(SyncObjectPosix_wfmo_info_st wait) {
int result = pthread_mutex_trylock(&wait.Waiter->Mutex); if (result == EBUSY) {
return false;
} assert(result == ); if (wait.Waiter->StillWaiting == false) {
--wait.Waiter->RefCount;
assert(wait.Waiter->RefCount >= );
bool destroy = wait.Waiter->RefCount == ;
result = pthread_mutex_unlock(&wait.Waiter->Mutex);
assert(result == );
if (destroy) {
wait.Waiter->Destroy();
delete wait.Waiter;
} return true;
} result = pthread_mutex_unlock(&wait.Waiter->Mutex);
assert(result == ); return false;
}
#endif // WFMO void* CreateEvent(void* lpEventAttributes, bool manualReset, bool initialState, void* lpName) {
SyncObjectPosix_event_st* event = new SyncObjectPosix_event_st; int result = pthread_cond_init(&event->CVariable, );
assert(result == ); result = pthread_mutex_init(&event->Mutex, );
assert(result == ); event->State = false;
event->AutoReset = !manualReset; if (initialState) {
result = SetEvent(event);
assert(result == );
} return event;
} int UnlockedWaitForEvent(void* event, uint64_t milliseconds) {
int result = ;
if (!((SyncObjectPosix_event_st*)event)->State) {
// Zero-timeout event state check optimization
if (milliseconds == ) {
return WAIT_TIMEOUT;
} timespec ts;
if (milliseconds != (uint64_t)-) {
timeval tv;
gettimeofday(&tv, NULL); uint64_t nanoseconds = ((uint64_t)tv.tv_sec) * * * +
milliseconds * * + ((uint64_t)tv.tv_usec) * ; ts.tv_sec = nanoseconds / / / ;
ts.tv_nsec = (nanoseconds - ((uint64_t)ts.tv_sec) * * * );
} do {
// Regardless of whether it's an auto-reset or manual-reset event:
// wait to obtain the event, then lock anyone else out
if (milliseconds != (uint64_t)-) {
result = pthread_cond_timedwait(&((SyncObjectPosix_event_st*)event)->CVariable, &((SyncObjectPosix_event_st*)event)->Mutex, &ts);
} else {
result = pthread_cond_wait(&((SyncObjectPosix_event_st*)event)->CVariable, &((SyncObjectPosix_event_st*)event)->Mutex);
}
} while (result == && !((SyncObjectPosix_event_st*)event)->State); if (result == && ((SyncObjectPosix_event_st*)event)->AutoReset) {
// We've only accquired the event if the wait succeeded
((SyncObjectPosix_event_st*)event)->State = false;
}
} else if (((SyncObjectPosix_event_st*)event)->AutoReset) {
// It's an auto-reset event that's currently available;
// we need to stop anyone else from using it
result = ;
((SyncObjectPosix_event_st*)event)->State = false;
}
// Else we're trying to obtain a manual reset event with a signaled state;
// don't do anything return result;
} int WaitForSingleObject(void* event, uint64_t milliseconds) {
int tempResult;
if (milliseconds == ) {
tempResult = pthread_mutex_trylock(&((SyncObjectPosix_event_st*)event)->Mutex);
if (tempResult == EBUSY) {
return WAIT_TIMEOUT;
}
} else {
tempResult = pthread_mutex_lock(&((SyncObjectPosix_event_st*)event)->Mutex);
} assert(tempResult == ); int result = UnlockedWaitForEvent(((SyncObjectPosix_event_st*)event), milliseconds); tempResult = pthread_mutex_unlock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(tempResult == ); if (result == ETIMEDOUT) {
return WAIT_TIMEOUT;
} return result;
} #ifdef WFMO
int WaitForMultipleEvents(void* *events, int count, bool waitAll,
uint64_t milliseconds) {
int unused;
return WaitForMultipleEvents(events, count, waitAll, milliseconds, unused);
} int WaitForMultipleEvents(void* *events, int count, bool waitAll,
uint64_t milliseconds, int &waitIndex) {
SyncObjectPosix_wfmo_st* wfmo = new SyncObjectPosix_wfmo_st; SyncObjectPosix_event_st** pp_events = (SyncObjectPosix_event_st**)events; int result = ;
int tempResult = pthread_mutex_init(&wfmo->Mutex, );
assert(tempResult == ); tempResult = pthread_cond_init(&wfmo->CVariable, );
assert(tempResult == ); SyncObjectPosix_wfmo_info_st waitInfo;
waitInfo.Waiter = wfmo;
waitInfo.WaitIndex = -; wfmo->WaitAll = waitAll;
wfmo->StillWaiting = true;
wfmo->RefCount = ; if (waitAll) {
wfmo->Status.EventsLeft = count;
} else {
wfmo->Status.FiredEvent = -;
} tempResult = pthread_mutex_lock(&wfmo->Mutex);
assert(tempResult == ); bool done = false;
waitIndex = -; for (int i = ; i < count; ++i) {
waitInfo.WaitIndex = i; // Must not release lock until RegisteredWait is potentially added
tempResult = pthread_mutex_lock(&pp_events[i]->Mutex);
assert(tempResult == ); // Before adding this wait to the list of registered waits, let's clean up old, expired
// waits while we have the event lock anyway
pp_events[i]->RegisteredWaits.erase(std::remove_if(pp_events[i]->RegisteredWaits.begin(),
pp_events[i]->RegisteredWaits.end(),
RemoveExpiredWaitHelper),
pp_events[i]->RegisteredWaits.end()); if (UnlockedWaitForEvent(events[i], ) == ) {
tempResult = pthread_mutex_unlock(&pp_events[i]->Mutex);
assert(tempResult == ); if (waitAll) {
--wfmo->Status.EventsLeft;
assert(wfmo->Status.EventsLeft >= );
} else {
wfmo->Status.FiredEvent = i;
waitIndex = i;
done = true;
break;
}
} else {
pp_events[i]->RegisteredWaits.push_back(waitInfo);
++wfmo->RefCount; tempResult = pthread_mutex_unlock(&pp_events[i]->Mutex);
assert(tempResult == );
}
} // We set the `done` flag above in case of WaitAny and at least one event was set.
// But we need to check again here if we were doing a WaitAll or else we'll incorrectly
// return WAIT_TIMEOUT.
if (waitAll && wfmo->Status.EventsLeft == ) {
done = true;
} timespec ts;
if (!done) {
if (milliseconds == ) {
result = WAIT_TIMEOUT;
done = true;
} else if (milliseconds != (uint64_t)-) {
timeval tv;
gettimeofday(&tv, NULL); uint64_t nanoseconds = ((uint64_t)tv.tv_sec) * * * +
milliseconds * * + ((uint64_t)tv.tv_usec) * ; ts.tv_sec = nanoseconds / / / ;
ts.tv_nsec = (nanoseconds - ((uint64_t)ts.tv_sec) * * * );
}
} while (!done) {
// One (or more) of the events we're monitoring has been triggered? // If we're waiting for all events, assume we're done and check if there's an event that
// hasn't fired But if we're waiting for just one event, assume we're not done until we
// find a fired event
done = (waitAll && wfmo->Status.EventsLeft == ) ||
(!waitAll && wfmo->Status.FiredEvent != -); if (!done) {
if (milliseconds != (uint64_t)-) {
result = pthread_cond_timedwait(&wfmo->CVariable, &wfmo->Mutex, &ts);
} else {
result = pthread_cond_wait(&wfmo->CVariable, &wfmo->Mutex);
} if (result != ) {
break;
}
}
} waitIndex = wfmo->Status.FiredEvent;
wfmo->StillWaiting = false; --wfmo->RefCount;
assert(wfmo->RefCount >= );
bool destroy = wfmo->RefCount == ;
tempResult = pthread_mutex_unlock(&wfmo->Mutex);
assert(tempResult == );
if (destroy) {
wfmo->Destroy();
delete wfmo;
} return result;
}
#endif // WFMO int CloseHandle(void* event) {
return DestroyEvent(event);
} int DestroyEvent(void* event) {
int result = ; #ifdef WFMO
result = pthread_mutex_lock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result == );
((SyncObjectPosix_event_st*)event)->RegisteredWaits.erase(std::remove_if(((SyncObjectPosix_event_st*)event)->RegisteredWaits.begin(),
((SyncObjectPosix_event_st*)event)->RegisteredWaits.end(),
RemoveExpiredWaitHelper),
((SyncObjectPosix_event_st*)event)->RegisteredWaits.end());
result = pthread_mutex_unlock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result == );
#endif result = pthread_cond_destroy(&((SyncObjectPosix_event_st*)event)->CVariable);
assert(result == ); result = pthread_mutex_destroy(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result == ); delete ((SyncObjectPosix_event_st*)event); return ;
} int SetEvent(void* event) {
int result = pthread_mutex_lock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result == ); ((SyncObjectPosix_event_st*)event)->State = true; // Depending on the event type, we either trigger everyone or only one
if (((SyncObjectPosix_event_st*)event)->AutoReset) {
#ifdef WFMO
while (!((SyncObjectPosix_event_st*)event)->RegisteredWaits.empty()) {
SyncObjectPosix_wfmo_info_st* i = &((SyncObjectPosix_event_st*)event)->RegisteredWaits.front(); result = pthread_mutex_lock(&i->Waiter->Mutex);
assert(result == ); --i->Waiter->RefCount;
assert(i->Waiter->RefCount >= );
if (!i->Waiter->StillWaiting) {
bool destroy = i->Waiter->RefCount == ;
result = pthread_mutex_unlock(&i->Waiter->Mutex);
assert(result == );
if (destroy) {
i->Waiter->Destroy();
delete i->Waiter;
}
((SyncObjectPosix_event_st*)event)->RegisteredWaits.pop_front();
continue;
} ((SyncObjectPosix_event_st*)event)->State = false; if (i->Waiter->WaitAll) {
--i->Waiter->Status.EventsLeft;
assert(i->Waiter->Status.EventsLeft >= );
// We technically should do i->Waiter->StillWaiting = Waiter->Status.EventsLeft
// != 0 but the only time it'll be equal to zero is if we're the last event, so
// no one else will be checking the StillWaiting flag. We're good to go without
// it.
} else {
i->Waiter->Status.FiredEvent = i->WaitIndex;
i->Waiter->StillWaiting = false;
} result = pthread_mutex_unlock(&i->Waiter->Mutex);
assert(result == ); result = pthread_cond_signal(&i->Waiter->CVariable);
assert(result == ); ((SyncObjectPosix_event_st*)event)->RegisteredWaits.pop_front(); result = pthread_mutex_unlock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result == ); return ;
}
#endif // WFMO
// event->State can be false if compiled with WFMO support
if (((SyncObjectPosix_event_st*)event)->State) {
result = pthread_mutex_unlock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result == ); result = pthread_cond_signal(&((SyncObjectPosix_event_st*)event)->CVariable);
assert(result == ); return ;
}
} else {
#ifdef WFMO
for (size_t i = ; i < ((SyncObjectPosix_event_st*)event)->RegisteredWaits.size(); ++i) {
SyncObjectPosix_wfmo_info_st* info = &((SyncObjectPosix_event_st*)event)->RegisteredWaits[i]; result = pthread_mutex_lock(&info->Waiter->Mutex);
assert(result == ); --info->Waiter->RefCount;
assert(info->Waiter->RefCount >= ); if (!info->Waiter->StillWaiting) {
bool destroy = info->Waiter->RefCount == ;
result = pthread_mutex_unlock(&info->Waiter->Mutex);
assert(result == );
if (destroy) {
info->Waiter->Destroy();
delete info->Waiter;
}
continue;
} if (info->Waiter->WaitAll) {
--info->Waiter->Status.EventsLeft;
assert(info->Waiter->Status.EventsLeft >= );
// We technically should do i->Waiter->StillWaiting = Waiter->Status.EventsLeft
// != 0 but the only time it'll be equal to zero is if we're the last event, so
// no one else will be checking the StillWaiting flag. We're good to go without
// it.
} else {
info->Waiter->Status.FiredEvent = info->WaitIndex;
info->Waiter->StillWaiting = false;
} result = pthread_mutex_unlock(&info->Waiter->Mutex);
assert(result == ); result = pthread_cond_signal(&info->Waiter->CVariable);
assert(result == );
}
((SyncObjectPosix_event_st*)event)->RegisteredWaits.clear();
#endif // WFMO
result = pthread_mutex_unlock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result == ); result = pthread_cond_broadcast(&((SyncObjectPosix_event_st*)event)->CVariable);
assert(result == );
} return ;
} int ResetEvent(void* event) {
int result = pthread_mutex_lock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result == ); ((SyncObjectPosix_event_st*)event)->State = false; result = pthread_mutex_unlock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result == ); return ;
} #ifdef PULSE
int PulseEvent(void* event) {
// This may look like it's a horribly inefficient kludge with the sole intention of reducing
// code duplication, but in reality this is what any PulseEvent() implementation must look
// like. The only overhead (function calls aside, which your compiler will likely optimize
// away, anyway), is if only WFMO auto-reset waits are active there will be overhead to
// unnecessarily obtain the event mutex for ResetEvent() after. In all other cases (being no
// pending waits, WFMO manual-reset waits, or any WFSO waits), the event mutex must first be
// released for the waiting thread to resume action prior to locking the mutex again in
// order to set the event state to unsignaled, or else the waiting threads will loop back
// into a wait (due to checks for spurious CVariable wakeups). int result = SetEvent(event);
assert(result == );
result = ResetEvent(event);
assert(result == ); return ;
}
#endif #else #include <mutex>
#include <condition_variable>
#include <chrono>
#include <functional> class SyncObjectPosix
{
public:
SyncObjectPosix(bool initial, bool manual) :
state(initial), manual(manual)
{
} void change(bool manual)
{
std::unique_lock<std::mutex> lock(mutex); this->manual = manual;
} void set()
{
std::unique_lock<std::mutex> lock(mutex); if (state)
return; state = true;
if (manual)
condition.notify_all();
else
condition.notify_one();
} void reset()
{
std::unique_lock<std::mutex> lock(mutex); state = false;
} void wait()
{
std::unique_lock<std::mutex> lock(mutex); condition.wait(lock, [this] { return state; }); if (!manual)
state = false;
} template<class Rep, class Period>
int wait(const std::chrono::duration<Rep, Period> &timeout)
{
std::unique_lock<std::mutex> lock(mutex); if (!condition.wait_for(lock, timeout, [this] {return state;} )) {
return WAIT_TIMEOUT;
}
//return; if (!manual)
state = false;
return ;
} private:
bool return_state() {
return state;
}; std::mutex mutex;
std::condition_variable condition;
bool state, manual;
}; inline void* CreateEvent(void* lpEventAttributes, BOOL bManualReset, BOOL bInitialState, void* lpName){
return (void*)(new SyncObjectPosix(bInitialState, bManualReset));
} inline void CloseHandle(void* p_this) {
delete (SyncObjectPosix*)p_this;
} inline int WaitForSingleObject(void* p_this, uint64_t milliseconds = -){
SyncObjectPosix* event_this = (SyncObjectPosix*)p_this;
return event_this->wait(std::chrono::milliseconds(milliseconds));
} inline int SetEvent(void* p_this){
SyncObjectPosix* event_this = (SyncObjectPosix*)p_this;
event_this->set();
return ;
} inline int ResetEvent(void* p_this){
SyncObjectPosix* event_this = (SyncObjectPosix*)p_this;
event_this->reset();
return ;
} #endif
使用pthread下的mutex与cond_var模拟windows下的event几个接口的更多相关文章
- eclipse下使用cygwin的方法(Windows下用eclipse玩gcc/g++和gdb)
明天就回国了,今晚回国前写写如何配置eclipse和CDT.这个配置方法网上讨论不是很多,可能用的人少,毕竟Windows上写C++程序多数喜欢VS,即使写的是Linux程序,很多人仍然会用VS(说只 ...
- Linux下TCP网络编程与基于Windows下C#socket编程间通信
一.linux下TCP网络编程基础,需要了解相关函数 Socket():用于套接字初始化. Bind():将 socket 与本机上的一个端口绑定,就可以在该端口监听服务请求. Listen():使s ...
- linux下启动mysql服务(类似于windows下net start mysql)
1.linux系统启动方式:service mysql start.其类似于windows下net start mysql
- 转:windows下命令行工具
转自: http://www.cnblogs.com/haochuang/p/5593411.html Windows下CMD不好用,远没有Linux,或者一些SSH工具用起来方便.其实Windows ...
- 在Linux下和Windows下遍历目录的方法及如何达成一致性操作
最近因为测试目的需要遍历一个目录下面的所有文件进行操作,主要是读每个文件的内容,只要知道文件名就OK了.在Java中直接用File类就可以搞定,因为Java中使用了组合模式,使得客户端对单个文件和文件 ...
- windows下编译php7图形库php_ui.dll
CSDN博客 具有图形化编程才有意思,这几天看到了php ui 图形扩展,只是现在只能下载php 7.1的 本次教程编译php7.2.6的 php ui 要是linux下编译起来比较简单 但是 win ...
- windows下mongodb基础玩法系列二CURD附加一
windows下mongodb基础玩法系列 windows下mongodb基础玩法系列一介绍与安装 windows下mongodb基础玩法系列二CURD操作(创建.更新.读取和删除) windows下 ...
- Windows下Nginx Virtual Host多站点配置详解
Windows下Nginx Virtual Host多站点配置详解 此教程适用于Windows系统已经配置好Nginx+Php+Mysql环境的同学. 如果您还未搭建WNMP环境,请查看 window ...
- windows下的c语言和linux 下的c语言以及C标准库和系统API
1.引出我们的问题? 标准c库都是一样的!大家想必都在windows下做过文件编程,在linux下也是一样的函数名,参数都一样.当时就有了疑问,因为我们非常清楚 其本质是不可能一样的,源于这是俩个操作 ...
随机推荐
- PAT Basic 1017 A除以B (20 分)
本题要求计算 /,其中 A 是不超过 1000 位的正整数,B 是 1 位正整数.你需要输出商数 Q 和余数 R,使得 A=B×Q+R 成立. 输入格式: 输入在一行中依次给出 A 和 B,中间以 1 ...
- web开发规范文档二
头部 header\hd 内容块 content\con\bd text txt title 尾部 footer 导航 nav\menu sub-n ...
- zencart通过产品id 批量添加推荐产品
1.修改 admin/featured.php 查找 pre_add_confirmation 将 pre_add_confirmation 与 break; 之间的代码,用下面的代码替换即可 &l ...
- mysql innodb存储引擎 锁 事务
以下内容翻译自mysql5.6官方手册. InnoDB是一种通用存储引擎,可平衡高可靠性和高性能.在MySQL 5.6中,InnoDB是默认的MySQL存储引擎.除非已经配置了不同的默认存储引擎, ...
- 利用pipework为docker容器设置固定IP
今天介绍如何在redhat/centos7系列机器上使用pipework为docker启动的容器指定一个固定ip,我们知道默认情况下,docker会使用 bridge网络模式为每一个启动的容器动态分配 ...
- Lambda学习总结(三)--方法引用
一.方法引用 1.1 方法引用含义 在学习了 Lambda 表达式之后,我们通常会使用 Lambda 表达式来创建匿名方法.但有的时候我们仅仅是需要调用一个已存在的方法.如下示例: @Function ...
- 【HDU6709】Fishing
题目大意:有 N 条鱼,每条鱼都有钓鱼和烤鱼的时间,钓鱼的时间均相同,每条鱼都有自己的烤鱼时间,一次只能烤一条鱼,且不能间断.现要求通过某种顺序将所有的鱼钓上来并烤完,求最小的时间是多少. 题解: 对 ...
- h5手机页面注册处理(短信验证)
//获取验证码 var wait = 60; function time(o) { if(wait == 0) { o.removeAttribute("disabled"); o ...
- Tomcat部署多个Springboot项目报错 InstanceNotFoundException: com.alibaba.druid:type=DruidDataSourceStat
在一个tomcat服务器下部署了多个采用阿里druid作为数据连接池,结果启动报错.原因是不能在一个tomcat服务器下不能直接部署多个druid作为数据连接池的项目,需要配置. 解决办法: 在spr ...
- HandlerAdapter解析参数过程之HandlerMethodArgumentResolver
在我们做Web开发的时候,会提交各种数据格式的请求,而我们的后台也会有相应的参数处理方式.SpringMVC就为我们提供了一系列的参数解析器,不管你是要获取Cookie中的值,Header中的值,JS ...