c++ - Waitpid和同步问题

标签 c++ linux multithreading process posix

我创建了一个简单的Process类来模仿std::thread。它应该只能在 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( 中的 waitpidm_pid = 0 之间调用 interrupt ) 那么我就杀死了一个不存在的进程,或者更糟糕的是,杀死了一个完全不相关的进程,但它恰好与旧进程具有相同的 pid。

交换join()中的m_pid = 0waitpid语句将使中断变得毫无用处,因为你可以预期第一个线程将花费大部分时间等待子进程终止。

所以我需要的是一个waitpid,它等待子进程终止,但使子进程保持僵尸状态,以便同时不能生成具有相同pid的进程。

有这样的事情或任何其他解决方案吗?

最佳答案

你是对的,一个阻塞waitpid(m_pid, ...);一个控制线程中的 m_pid = 0 和另一个控制线程中的 kill(m_pid, ...) 将发生竞争。添加互斥体不会因为您指出的原因而有所帮助 - 服务员必须等待并更新一些全局信息,但必须允许 killer (间接)中断等待。

(我将忽略有关模仿 std::thread 的部分,例如,它不支持中断。)

相反,您可以依赖继承的 pipe ,并确保子进程继承管道的写端,而将读端留给父进程。当子进程终止时,读结束将指示 EOF,但外部资源(僵尸进程条目)将保留,直到显式收获。此方法并非万无一失,因为子进程可能会 fork 或 exec 或以其他方式意外地关闭或传递其写入端 fd。

顺便说一句,您可以设计更复杂的解决方案。例如,您可以生成一个 secret 线程来 waitpidkill 子进程,然后您的 interrupt 方法可以使用实时信号。您也可以接管整个父进程的 SIGCHLD 处理。不过,这些都是重量级的并且容易出错。

关于c++ - Waitpid和同步问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28898268/

相关文章:

c - 在 linux 上删除终端输出

java - 关闭执行器服务中的线程而不关闭它

c++ - 抑制特定代码行的 -Wconversion

java - 从 JNI 到 Java 的字符 vector

c++ - 使用 C++ 在 Windows 中输入笔

java - 使用 java runtime exec 运行连续的命令 Linux

python - 使用 Python 处理许多文件

c++ - MongoDB C++:mongocxx::pool 线程安全吗?

c++ - 使用新的 C 和 C++ 标准的 POSIX 多线程会发生什么?

c++ - 为什么在函数定义中缺少形式参数名称的 C++ 代码编译时没有警告?