使用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下也是一样的函数名,参数都一样.当时就有了疑问,因为我们非常清楚 其本质是不可能一样的,源于这是俩个操作 ...
随机推荐
- C#实现下载Demo
using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Secu ...
- mysql自增字段AUTO_INCREMENT重排或归零
由于删除了某些记录行,导致自增字段不连续了,重排或归零的方法: 方法1:truncate table 你的表名//这样不但重新定位自增的字段,而且会将表里的数据全部删除,慎用! 方法2:delete ...
- GlusterFS ——分布式卷
GlusterFS概述 全部部署GlusterFS文件系统地址:https://www.cnblogs.com/Mercury-linux/p/12050389.html GlusterFS系统是一个 ...
- 清空DataGridView
DataTable dt = (DataTable)dgv.DataSource; dt.Rows.Clear(); dgv.DataSource = dt;
- 京东POP店铺使用京东物流切仓操作方法
首先进入京东物流工作台:https://wl.jdwl.com/ 在运营管理中,点击店铺商品 然后看截图操作
- MessagePack Java 0.6.X 快速开始指南 - 安装
0.6.x 版本的 MessagePack 已经过期被淘汰了.如果你现在开始使用 MessagePack 话,请不要使用这个版本. 我们再这里保留 0.6.x 版本的内容主要用于参考用途. 最新的 M ...
- Angular 如何修改启动的端口
在默认的情况下 Angular 启动使用的是端口 4200. 如果修改这个启动的端口,比如说我们希望再 4100 端口上启动? 可以在启动的时候添加端口参数 --port. 例如使用下面的启动命令: ...
- 快速搭建 Serverless 人脸识别离线服务
简介 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute):函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算准 ...
- 论文阅读:NETFPGA SUME: TOWARD 100 GBPS AS RESEARCH COMMODITY
摘要: 数据中心网络的需求增长意味着许多组成技术不在研究社区的预算之内. NETFPGA SUME是基于FPGA的PCI Express板,具有I / O功能,可作为网络接口卡,多端口开关,防火墙或测 ...
- A. Even Substrings
A. Even Substrings time limit per test 0.5 seconds memory limit per test 256 megabytes input standar ...