Windows 命名信号量未被锁定
Windows Named Semaphore Not Getting Locked
我正在开发 C++ class 并调用 Windows API C 库。
我正在使用信号量执行任务,假设我有两个进程:
ProcessA 有两个信号量:
Global\processA_receiving_semaphore
Global\processA_waiting_semaphore
ProcessB 有两个信号量:
Global\processB_receiving_semaphore
Global\processB_waiting_semaphore
我在每个进程中有两个线程:
正在进程A中发送线程:
Wait on "Global\processB_waiting_semaphore"
// do something
Signal "Global\processB_receiving_semaphore"
processB 上的接收线程:
Wait on "Global\processB_receiving_semaphore"
// do something
Signal "Global\processB_waiting_semaphore
我删除了所有发布“Global\processB_waiting_semaphore”的代码,但它仍然可以获取。在那个信号量上调用 WaitForSingleObject
总是 returns 成功等待并立即。我尝试将超时时间设置为 0,它仍然在没有释放信号量的情况下获取信号量。
接收信号量有initial count = 0
和max count = 1
,而等待信号量有initial count = 1
和max count = 1
。
在接收信号量上调用 WaitForSingleObject
效果很好,并且会阻塞直到被其他进程释放。问题出在等待信号量上,我不明白为什么。代码非常大,我已经确保信号量的名称设置正确。
这是一个常见问题吗?如果您需要更多解释,请发表评论,我将修改 post.
编辑:添加的代码:
接收器信号量:
bool intr_process_comm::create_rcvr_semaphores()
{
std::cout << "\n Creating semaphore: " << "Global\" << this_name << "_rcvr_sem";
rcvr_sem = CreateSemaphore(NULL, 0, 1, ("Global\" + this_name + "_rcvr_sem").c_str());
std::cout << "\n Creating semaphore: " << "Global\" << this_name << "_wait_sem";
wait_sem = CreateSemaphore(NULL, 1, 1, ("Global\" + this_name + "_wait_sem").c_str());
return (rcvr_sem && wait_sem);
}
发件人信号量:
// this sender connects to the wait semaphore in the target process
sndr_sem = OpenSemaphore(SEMAPHORE_MODIFY_STATE, FALSE, ("Global\" + target_name + "_wait_sem").c_str());
// this target connects to the receiver semaphore in the target process
trgt_sem = OpenSemaphore(SEMAPHORE_MODIFY_STATE, FALSE, ("Global\" + target_name + "_rcvr_sem").c_str());
DWORD intr_process_locking::wait(unsigned long period)
{
return WaitForSingleObject(sndr_sem, period);
}
void intr_process_locking::signal()
{
ReleaseSemaphore(trgt_sem, 1, 0);
}
接收线程函数:
void intr_process_comm::rcvr_thread_proc()
{
while (conn_state == intr_process_comm::opened) {
try {
// wait on rcvr_semaphore for an infinite time
WaitForSingleObject(rcvr_sem, INFINITE);
if (inner_release) // if the semaphore was released within this process
return;
// once signaled by another process, get the message
std::string msg_str((LPCSTR)hmf_mapview);
// signal one of the waiters that want to put messages
// in this process's memory area
//
// this doesn't change ANYTHING in execution, commented or not..
//ReleaseSemaphore(wait_sem, 1, 0);
// put this message in this process's queue
Msg msg = Msg::from_xml(msg_str);
if (msg.command == "connection")
process_connection_message(msg);
in_messages.enQ(msg);
//std::cout << "\n Message: \n"<< msg << "\n";
}
catch (std::exception e) {
std::cout << "\n Ran into trouble getting the message. Details: " << e.what();
}
}
}
发送线程函数:
void intr_process_comm::sndr_thread_proc()
{
while (conn_state == intr_process_comm::opened ||
(conn_state == intr_process_comm::closing && out_messages.size() > 0)
) {
// pull a message out of the queue
Msg msg = out_messages.deQ();
if (connections.find(msg.destination) == connections.end())
connections[msg.destination].connect(msg.destination);
if (connections[msg.destination].connect(msg.destination)
!= intr_process_locking::state::opened) {
blocked_messages[msg.destination].push_back(msg);
continue;
}
// THIS ALWAYS GETS GETS WAIT_OBJECT_0 RESULT
DWORD wait_result = connections[msg.destination].wait(wait_timeout);
if (wait_result == WAIT_TIMEOUT) { // <---- THIS IS NEVER TRUE
out_messages.enQ(msg);
continue;
}
// do things here
// release the receiver semaphore in the other process
connections[msg.destination].signal();
}
}
澄清一些事情:
发件人中的 trgt_sem
是收件人中的 rcvr_sem
。
发送方的`sndr_sem'是接收方的'wait_sem"。
如果将超时设置为 0 WaitForSingleObject 将始终 return 立即,成功的 WaitForSingleObject 将 return WAIT_OBJECT_0 (恰好值为 0),WFSO 不像大多数由非零 return.
指示成功的 API
调用 WaitForSingleObject
一些句柄:
The handle must have the SYNCHRONIZE
access right.
但您打开信号灯时只有 SEMAPHORE_MODIFY_STATE
访问权限。使用此访问可能调用 ReleaseSemaphore
(此句柄必须具有 SEMAPHORE_MODIFY_STATE
访问权限)但调用 WaitForSingleObject
失败,结果为 WAIT_FAILED
.在此之后调用 GetLastError()
必须 return ERROR_ACCESS_DENIED
。
因此,如果我们想同时调用 ReleaseSemaphore
和任何等待函数 - 我们需要对句柄具有 SEMAPHORE_MODIFY_STATE | SYNCHRONIZE
访问权限。所以需要用代码
打开
OpenSemaphore(SEMAPHORE_MODIFY_STATE|SYNCHRONIZE, )
当然还要经常检查 api return 值和错误代码可以节省很多时间
我正在开发 C++ class 并调用 Windows API C 库。
我正在使用信号量执行任务,假设我有两个进程:
ProcessA 有两个信号量:
Global\processA_receiving_semaphore
Global\processA_waiting_semaphore
ProcessB 有两个信号量:
Global\processB_receiving_semaphore
Global\processB_waiting_semaphore
我在每个进程中有两个线程:
正在进程A中发送线程:
Wait on "Global\processB_waiting_semaphore"
// do something
Signal "Global\processB_receiving_semaphore"
processB 上的接收线程:
Wait on "Global\processB_receiving_semaphore"
// do something
Signal "Global\processB_waiting_semaphore
我删除了所有发布“Global\processB_waiting_semaphore”的代码,但它仍然可以获取。在那个信号量上调用 WaitForSingleObject
总是 returns 成功等待并立即。我尝试将超时时间设置为 0,它仍然在没有释放信号量的情况下获取信号量。
接收信号量有initial count = 0
和max count = 1
,而等待信号量有initial count = 1
和max count = 1
。
在接收信号量上调用 WaitForSingleObject
效果很好,并且会阻塞直到被其他进程释放。问题出在等待信号量上,我不明白为什么。代码非常大,我已经确保信号量的名称设置正确。
这是一个常见问题吗?如果您需要更多解释,请发表评论,我将修改 post.
编辑:添加的代码:
接收器信号量:
bool intr_process_comm::create_rcvr_semaphores()
{
std::cout << "\n Creating semaphore: " << "Global\" << this_name << "_rcvr_sem";
rcvr_sem = CreateSemaphore(NULL, 0, 1, ("Global\" + this_name + "_rcvr_sem").c_str());
std::cout << "\n Creating semaphore: " << "Global\" << this_name << "_wait_sem";
wait_sem = CreateSemaphore(NULL, 1, 1, ("Global\" + this_name + "_wait_sem").c_str());
return (rcvr_sem && wait_sem);
}
发件人信号量:
// this sender connects to the wait semaphore in the target process
sndr_sem = OpenSemaphore(SEMAPHORE_MODIFY_STATE, FALSE, ("Global\" + target_name + "_wait_sem").c_str());
// this target connects to the receiver semaphore in the target process
trgt_sem = OpenSemaphore(SEMAPHORE_MODIFY_STATE, FALSE, ("Global\" + target_name + "_rcvr_sem").c_str());
DWORD intr_process_locking::wait(unsigned long period)
{
return WaitForSingleObject(sndr_sem, period);
}
void intr_process_locking::signal()
{
ReleaseSemaphore(trgt_sem, 1, 0);
}
接收线程函数:
void intr_process_comm::rcvr_thread_proc()
{
while (conn_state == intr_process_comm::opened) {
try {
// wait on rcvr_semaphore for an infinite time
WaitForSingleObject(rcvr_sem, INFINITE);
if (inner_release) // if the semaphore was released within this process
return;
// once signaled by another process, get the message
std::string msg_str((LPCSTR)hmf_mapview);
// signal one of the waiters that want to put messages
// in this process's memory area
//
// this doesn't change ANYTHING in execution, commented or not..
//ReleaseSemaphore(wait_sem, 1, 0);
// put this message in this process's queue
Msg msg = Msg::from_xml(msg_str);
if (msg.command == "connection")
process_connection_message(msg);
in_messages.enQ(msg);
//std::cout << "\n Message: \n"<< msg << "\n";
}
catch (std::exception e) {
std::cout << "\n Ran into trouble getting the message. Details: " << e.what();
}
}
}
发送线程函数:
void intr_process_comm::sndr_thread_proc()
{
while (conn_state == intr_process_comm::opened ||
(conn_state == intr_process_comm::closing && out_messages.size() > 0)
) {
// pull a message out of the queue
Msg msg = out_messages.deQ();
if (connections.find(msg.destination) == connections.end())
connections[msg.destination].connect(msg.destination);
if (connections[msg.destination].connect(msg.destination)
!= intr_process_locking::state::opened) {
blocked_messages[msg.destination].push_back(msg);
continue;
}
// THIS ALWAYS GETS GETS WAIT_OBJECT_0 RESULT
DWORD wait_result = connections[msg.destination].wait(wait_timeout);
if (wait_result == WAIT_TIMEOUT) { // <---- THIS IS NEVER TRUE
out_messages.enQ(msg);
continue;
}
// do things here
// release the receiver semaphore in the other process
connections[msg.destination].signal();
}
}
澄清一些事情:
发件人中的trgt_sem
是收件人中的 rcvr_sem
。
`sndr_sem'是接收方的'wait_sem"。
如果将超时设置为 0 WaitForSingleObject 将始终 return 立即,成功的 WaitForSingleObject 将 return WAIT_OBJECT_0 (恰好值为 0),WFSO 不像大多数由非零 return.
指示成功的 API调用 WaitForSingleObject
一些句柄:
The handle must have the
SYNCHRONIZE
access right.
但您打开信号灯时只有 SEMAPHORE_MODIFY_STATE
访问权限。使用此访问可能调用 ReleaseSemaphore
(此句柄必须具有 SEMAPHORE_MODIFY_STATE
访问权限)但调用 WaitForSingleObject
失败,结果为 WAIT_FAILED
.在此之后调用 GetLastError()
必须 return ERROR_ACCESS_DENIED
。
因此,如果我们想同时调用 ReleaseSemaphore
和任何等待函数 - 我们需要对句柄具有 SEMAPHORE_MODIFY_STATE | SYNCHRONIZE
访问权限。所以需要用代码
OpenSemaphore(SEMAPHORE_MODIFY_STATE|SYNCHRONIZE, )
当然还要经常检查 api return 值和错误代码可以节省很多时间