waitpid 和同步问题
Waitpid and synchronization issues
我创建了一个模仿 std::thread
的简单 Process
class。它应该只适用于 linux。
struct Process
{
Process(/*...*/) { /* fork + join, initialize m_pid */ }
~Process() { assert(!joinable()); }
bool joinable() const { return m_pid != 0; }
void join()
{
assert (joinable());
int status;
waitpid(m_pid, &status, 0);
m_pid = 0;
}
private:
std::atomic<pid_t> m_pid;
};
我有一个额外的要求:我需要能够从另一个线程停止进程。
例如:
Process p(/* ... */ );
Thread 1:
p.join();
Thread 2:
p.interrupt();
如何实现线程安全的Process:interrupt
?我的第一个想法是这样的:
void Process::interrupt()
{
if (m_pid)
kill(m_pid, SIGTERM);
}
不幸的是,我不确定这是否有效,因为如果在 join()
中的 waitpid
和 m_pid = 0
之间调用 interrupt
那么我将杀死一个不存在的进程,或者更糟的是一个完全不相关的进程恰好与旧进程具有相同的 pid。
在 join()
中交换 m_pid = 0
和 waitpid
语句会使中断变得毫无用处,因为您可以预期第一个线程将花费大部分时间等待子进程终止。
所以我需要的是 waitpid
等待子进程终止但保持子进程处于僵尸状态,以便同时不会产生具有相同 pid 的进程。
有这样的事情或者其他解决办法吗?
你是对的,一个控制线程中的阻塞 waitpid(m_pid, ...); m_pid = 0
和另一个控制线程中的 kill(m_pid, ...)
将竞争。由于您指出的原因,添加互斥锁无济于事 - 服务员必须等待 和 更新一些全局信息,但必须允许杀手(间接)中断等待。
(我将忽略关于模仿 std::thread
的部分,例如不支持中断。)
相反,您可以依赖继承的 pipe
,并确保 child 进程继承管道的 write-end,留下 parent 和 read-end。 read-end 将在 child 终止时指示 EOF,但外部资源(僵尸进程条目)将保留,直到明确收割。此方法并非万无一失,因为 child 可能会分叉或执行或以其他方式关闭或意外传递其 write-end fd。
顺便说一句,您可以设计更复杂的解决方案。例如,您可以为 waitpid
和 kill
进程生成一个秘密线程,然后您的 interrupt
方法可以使用 real-time 中断该线程信号。您也可以接管整个 parent 进程的 SIGCHLD 处理。不过,这些都是重量级的 error-prone。
我创建了一个模仿 std::thread
的简单 Process
class。它应该只适用于 linux。
struct Process
{
Process(/*...*/) { /* fork + join, initialize m_pid */ }
~Process() { assert(!joinable()); }
bool joinable() const { return m_pid != 0; }
void join()
{
assert (joinable());
int status;
waitpid(m_pid, &status, 0);
m_pid = 0;
}
private:
std::atomic<pid_t> m_pid;
};
我有一个额外的要求:我需要能够从另一个线程停止进程。
例如:
Process p(/* ... */ );
Thread 1:
p.join();
Thread 2:
p.interrupt();
如何实现线程安全的Process:interrupt
?我的第一个想法是这样的:
void Process::interrupt()
{
if (m_pid)
kill(m_pid, SIGTERM);
}
不幸的是,我不确定这是否有效,因为如果在 join()
中的 waitpid
和 m_pid = 0
之间调用 interrupt
那么我将杀死一个不存在的进程,或者更糟的是一个完全不相关的进程恰好与旧进程具有相同的 pid。
在 join()
中交换 m_pid = 0
和 waitpid
语句会使中断变得毫无用处,因为您可以预期第一个线程将花费大部分时间等待子进程终止。
所以我需要的是 waitpid
等待子进程终止但保持子进程处于僵尸状态,以便同时不会产生具有相同 pid 的进程。
有这样的事情或者其他解决办法吗?
你是对的,一个控制线程中的阻塞 waitpid(m_pid, ...); m_pid = 0
和另一个控制线程中的 kill(m_pid, ...)
将竞争。由于您指出的原因,添加互斥锁无济于事 - 服务员必须等待 和 更新一些全局信息,但必须允许杀手(间接)中断等待。
(我将忽略关于模仿 std::thread
的部分,例如不支持中断。)
相反,您可以依赖继承的 pipe
,并确保 child 进程继承管道的 write-end,留下 parent 和 read-end。 read-end 将在 child 终止时指示 EOF,但外部资源(僵尸进程条目)将保留,直到明确收割。此方法并非万无一失,因为 child 可能会分叉或执行或以其他方式关闭或意外传递其 write-end fd。
顺便说一句,您可以设计更复杂的解决方案。例如,您可以为 waitpid
和 kill
进程生成一个秘密线程,然后您的 interrupt
方法可以使用 real-time 中断该线程信号。您也可以接管整个 parent 进程的 SIGCHLD 处理。不过,这些都是重量级的 error-prone。