为什么我的分叉进程上的信号量没有被释放?
Why is my semaphore on a forked process not being released?
我在使用 POSIX 信号量释放分叉进程时遇到问题。通过在 fork
和 exec
之后调用 运行 进程的另一个实例来启动分叉进程。有时 child 会被释放,有时不会。
它是一个名为 semaphore 的 POSIX 共享内存,奇怪的是它有时会起作用。我检查了其他解决方案,但他们的解决方案对我没有帮助。
void init()
{
...
sem_unlink(sem_name.c_str());
if (parent_process)
{
sem_t* semaphore = sem_open(sem_name.c_str(), O_CREAT | O_RDWR, 0);
if (SEM_FAILED == semaphore)
{
display_error();
}
sem_close(semaphore);
}
child_pid = fork();
if (child_pid == -1)
{
display_error();
}
else if (child_pid == 0)
{
int ret = execve(program_name, args, env);
if (ret == -1)
{
display_error();
}
}
else
{
// rest of code
}
...
}
我让 child 进程在另一个具有此功能的 class 中等待释放:
void wait_until_released()
{
if (!parent_process)
{
sem_t* semaphore = sem_open(sem_name.c_str(), O_CREAT | O_RDWR, 0);
if (SEM_FAILED == semaphore)
{
display_error();
}
sem_wait(semaphore);
sem_close(semaphore);
sem_unlink(semaphore);
}
}
post 是在代码中的另一个位置完成的:
void release_child()
{
sem_t* semaphore = sem_open(sem_name.c_str(), O_CREAT | O_RDWR, 0);
if (SEM_FAILED == semaphore)
{
display_error();
}
if (sem_post(semaphore) != 0)
{
display_error();
}
sem_close(semaphore);
sem_unlink(semaphore);
}
这个问题的发生最终是因为我在 POSIX 信号量上调用 sem_unlink
,然后在分叉进程中对其进行等待。当所有文件描述符都对信号量调用 sem_close
时,调用 sem_unlink
会导致信号量被删除。从本质上讲,这阻止了我的 child 进程能够使用该实例并完全被释放。
这仅在某些时候有效,因为有一个基本假设,即在我们调用 release_child
时 child 已经在等待释放。这并不能保证,这是有时但并非一直有效的原因。如果我们在 child 调用 sem_wait
之前调用 release_child
,那么我们将完全删除信号量,并且 child 创建他们自己的信号量版本,该版本永远不会得到 post编辑到。
通过将 unlink
调用移到第一组代码中的 if 语句之后,我阻止了 child 进程在等待信号量之前删除它。此外,通过从 release_child
和 wait_until_released
函数中的 sem_open
中删除 O_CREAT
标志以及从 release_child
函数中删除 sem_unlink
,我阻止了child 从创建自己的信号量。
我想记录下我看到的行为,因为那才是真正给我带来问题的原因。在调试和修复这个问题的过程中,我了解到如果 parent 创建了信号量但没有关闭它,那么 child 正在调用 sem_unlink
并创建它自己的版本一样的名字。这让我相信原来的信号量仍然存在,但 sem_post
and/or sem_wait
不工作。
因此,在执行信号量时,请注意 post、wait、close 和 unlink 调用。尤其是涉及到分叉进程时!!
我在使用 POSIX 信号量释放分叉进程时遇到问题。通过在 fork
和 exec
之后调用 运行 进程的另一个实例来启动分叉进程。有时 child 会被释放,有时不会。
它是一个名为 semaphore 的 POSIX 共享内存,奇怪的是它有时会起作用。我检查了其他解决方案,但他们的解决方案对我没有帮助。
void init()
{
...
sem_unlink(sem_name.c_str());
if (parent_process)
{
sem_t* semaphore = sem_open(sem_name.c_str(), O_CREAT | O_RDWR, 0);
if (SEM_FAILED == semaphore)
{
display_error();
}
sem_close(semaphore);
}
child_pid = fork();
if (child_pid == -1)
{
display_error();
}
else if (child_pid == 0)
{
int ret = execve(program_name, args, env);
if (ret == -1)
{
display_error();
}
}
else
{
// rest of code
}
...
}
我让 child 进程在另一个具有此功能的 class 中等待释放:
void wait_until_released()
{
if (!parent_process)
{
sem_t* semaphore = sem_open(sem_name.c_str(), O_CREAT | O_RDWR, 0);
if (SEM_FAILED == semaphore)
{
display_error();
}
sem_wait(semaphore);
sem_close(semaphore);
sem_unlink(semaphore);
}
}
post 是在代码中的另一个位置完成的:
void release_child()
{
sem_t* semaphore = sem_open(sem_name.c_str(), O_CREAT | O_RDWR, 0);
if (SEM_FAILED == semaphore)
{
display_error();
}
if (sem_post(semaphore) != 0)
{
display_error();
}
sem_close(semaphore);
sem_unlink(semaphore);
}
这个问题的发生最终是因为我在 POSIX 信号量上调用 sem_unlink
,然后在分叉进程中对其进行等待。当所有文件描述符都对信号量调用 sem_close
时,调用 sem_unlink
会导致信号量被删除。从本质上讲,这阻止了我的 child 进程能够使用该实例并完全被释放。
这仅在某些时候有效,因为有一个基本假设,即在我们调用 release_child
时 child 已经在等待释放。这并不能保证,这是有时但并非一直有效的原因。如果我们在 child 调用 sem_wait
之前调用 release_child
,那么我们将完全删除信号量,并且 child 创建他们自己的信号量版本,该版本永远不会得到 post编辑到。
通过将 unlink
调用移到第一组代码中的 if 语句之后,我阻止了 child 进程在等待信号量之前删除它。此外,通过从 release_child
和 wait_until_released
函数中的 sem_open
中删除 O_CREAT
标志以及从 release_child
函数中删除 sem_unlink
,我阻止了child 从创建自己的信号量。
我想记录下我看到的行为,因为那才是真正给我带来问题的原因。在调试和修复这个问题的过程中,我了解到如果 parent 创建了信号量但没有关闭它,那么 child 正在调用 sem_unlink
并创建它自己的版本一样的名字。这让我相信原来的信号量仍然存在,但 sem_post
and/or sem_wait
不工作。
因此,在执行信号量时,请注意 post、wait、close 和 unlink 调用。尤其是涉及到分叉进程时!!