跨平台调试时,使用Windows的Semaphore模拟Linux下阻塞等候信号量的值为零

61 篇文章 0 订阅
58 篇文章 0 订阅
Linux下的信号量有一个有趣的特性,你可以让信号量阻塞,等候任何一个期望的值。这里,以阻塞等候信号量的值为零说明。
Linux的代码如下:
sem_buf.sem_num = 0;
sem_buf.sem_op  = 0;
sem_buf.sem_flg = 0;


if (semop(mtx, &sem_buf, 1) == -1) {
if (EINTR != errno) {
return -1;
}
} else {
return 0;
}

Windows下先创建进程间通信的Semaphore,例如:
mtx = OpenSemaphore(SEMAPHORE_ALL_ACCESS/*SEMAPHORE_MODIFY_STATE*/, FALSE, TEXT(name));
if (NULL != mtx) {
fprintf(stderr, "Open mutex[%d] %s success! \n", i, name);  
} else {
fprintf(stderr, "Open mutex[%d] %s failed! create... \n", i, name);  
mtx = CreateSemaphore( 
NULL,           // default security attributes
value, // initial count
20, // maximum count
TEXT(name));    // unnamed semaphore

}

Windows下模拟阻塞等候信号量为零需要一点技巧,MSDN中的如下说明:
It is not possible to reduce the semaphore object count using ReleaseSemaphore, because lReleaseCount cannot be a negative number. To temporarily restrict or reduce access, create a loop in which you call the WaitForSingleObject function with a time-out interval of zero until the semaphore count has been reduced sufficiently. (Note that other threads can reduce the count while this loop is being executed.) To restore access, call ReleaseSemaphore with the release count equal to the number of times WaitForSingleObject was called in the loop. 


按MSDN的说明,如下处理,其实不能真正地解决问题,会引起两个进程间执行顺序的错误。
LONG prevCount = 0;
do {
prevCount = 0;
ReleaseSemaphore(mtx, 1, &prevCount); // 这里信号量+1,消费者进程首先抢到CPU运行,引起执行顺序错误
WaitForSingleObject(mtx, INFINITE);
if (0 != prevCount) {
Sleep(50);
}
} while (0 != prevCount);


那么,很自然地,查询Semaphore当前的值,应该可以实现的吧。然而,这样执行ReleaseSemaphore(mtx, 0, &prevCount)会返回错误号7(参数错误),而且prevCount为0,MSDN是这样说的:
lReleaseCount [in] 
The amount by which the semaphore object's current count is to be increased. The value must be greater than zero. If the specified amount would cause the semaphore's count to exceed the maximum count that was specified when the semaphore was created, the count is not changed and the function returns FALSE.


[吐槽] 实在不知道MS的大牛们设计ReleaseSemaphore函数时怎么想的,这样调用ReleaseSemaphore(handle, 0, &prevCount)时prevCount返回当前的信号量值不是很好么?要不设计另外一个函数可以查询啊!Linuxer们的设计还是要简练实用一些。记得好像libevent源码里面有段注释说MS有些API什么来着的? a shit,真有点儿呢


怎么办呢?设计一个共享内存,保存信号量的引用计数,然后,WaitForSingleObject减1,ReleaseSemaphore加1,模拟阻塞等候信号量的函数中查询共享内存呗。


class refermanager {
public:
typedef struct refer_t_ {
ISEM_KEY key;
INT32S refers;
}refer_t;
public:
refermanager() {
HANDLE hMap = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, name);
int size = MAX_REFERS_ITEMS * sizeof(refer_t);
if (NULL == hMap) {
hMap = ::CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
size,
name);
}
if (NULL != hMap) {
pMemory = ::MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
} else {
pMemory = NULL;
}
}
~refermanager() {
};
static void Set(int key, int value);
static void Inc(int key, int value);
static void Dec(int key, int value);
static int  Get(int key);
protect:
void * pMemory;
}


static refermanager g_manager_obj;


然后, ReleaseSemaphore(mtx, n, &prevCount)之后,执行refermanager::Inc(key, n); WaitForSingleObject之后,执行refermanager::Dec(key,1)。阻塞等候信号量值为零的函数中,如此实现,
for (int n = 1; n > 0; ) {
n = refermanager::Get(key);
if (n > 0) {
Sleep(50);
}
}


更进一步,为了防止两个进程同一时刻访问pMemory,还需要为pMemory加锁保护,用Mutex或者Semaphore都可以,网上有大把的教程,这里就不啰嗦了,祝Windows下的Linuxer们玩得愉快。











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值