当 parent 进程有很多线程、套接字和 IPC 时,在分叉 (child) 进程中调用 system()
Call system() inside forked (child) process, when parent process has many threads, sockets and IPC
我有一个有很多线程的程序。有些线程是 TCP 服务器...每个服务器都会触发新线程来处理任何新连接。
在处理单个客户端的线程之一中,我调用了 fork()。 child 进程调用 setpgid() (创建一个新组)然后调用 system() (C/C++ 标准库的函数)。 parent 进程不断小睡(usleep() 函数)并检查时间限制。如果在 child 从 system() 处理 returns 之前超过了时间限制,parent SIGKILLs child.
我正在使用:Linux (Ubuntu)、pthreads 等。只有 C/C++ 标准库!
我的问题:child 进程上的所有线程和 TCP 套接字发生了什么?这些东西是从parent进程继承来的吗? child 和 parent 运行 所有这些线程和 TCP 服务器会同时进行吗?这对我来说毫无意义......当 parent SIGKILLs child 时,套接字将仅在 child 内关闭,还是在 parent 内关闭?
目前,我实际上正在使用 exec() 来清理 child 进程的整个映像,但如果安全的话,我宁愿直接调用 system()。
文件描述符(a.k.a.fds),例如 TCP 套接字,是跨叉继承的。文件或设备 "behind" 它们通常保持打开和可用状态,直到它的最后一个文件描述符在进程终止时被关闭或关闭。因此 SIGKILL'ing child 不会影响与 parent.
共享的 TCP 套接字
但是,只有 fork()ing 线程在 child 中执行。不会复制其他控制线程。您的情况看起来像这样:
+-- PID 100 -------------+ # parent
| fds: 0, 1, 2, 3 ... N | # fds: stdin, stdout, stderr, socket ... socket
| threads: |
| 0 (main) |
| 1 (tcp server) |
| 2 (forky) ---------(fork(2))-+
| ... | |
| N (tcp server) | |
+------------------------+ |
|
|
+-- PID 101 -------------+ # child
| fds: 0, 1, 2, 3 ... N | # fds: inherited
| threads: |
| 0 (copy of forky) | # will exec() ?
+------------------------+
调用 exec
将用一些文本 main()
替换 PID 101 过程映像(并关闭任何标记为 FD_CLOEXEC 的文件描述符)。相比之下,调用 system("whatever")
可能会产生至少两个进程:一个 (grand)child /bin/sh
和一个 (great) grandchild "whatever"。
混合使用线程、分支和共享资源很容易让自己感到困惑,尤其是当像 system()
这样的旧接口被混入其中时。慢慢来,在不需要时明确丢弃不需要的资源,一次解决一件事。
我有一个有很多线程的程序。有些线程是 TCP 服务器...每个服务器都会触发新线程来处理任何新连接。
在处理单个客户端的线程之一中,我调用了 fork()。 child 进程调用 setpgid() (创建一个新组)然后调用 system() (C/C++ 标准库的函数)。 parent 进程不断小睡(usleep() 函数)并检查时间限制。如果在 child 从 system() 处理 returns 之前超过了时间限制,parent SIGKILLs child.
我正在使用:Linux (Ubuntu)、pthreads 等。只有 C/C++ 标准库!
我的问题:child 进程上的所有线程和 TCP 套接字发生了什么?这些东西是从parent进程继承来的吗? child 和 parent 运行 所有这些线程和 TCP 服务器会同时进行吗?这对我来说毫无意义......当 parent SIGKILLs child 时,套接字将仅在 child 内关闭,还是在 parent 内关闭?
目前,我实际上正在使用 exec() 来清理 child 进程的整个映像,但如果安全的话,我宁愿直接调用 system()。
文件描述符(a.k.a.fds),例如 TCP 套接字,是跨叉继承的。文件或设备 "behind" 它们通常保持打开和可用状态,直到它的最后一个文件描述符在进程终止时被关闭或关闭。因此 SIGKILL'ing child 不会影响与 parent.
共享的 TCP 套接字但是,只有 fork()ing 线程在 child 中执行。不会复制其他控制线程。您的情况看起来像这样:
+-- PID 100 -------------+ # parent
| fds: 0, 1, 2, 3 ... N | # fds: stdin, stdout, stderr, socket ... socket
| threads: |
| 0 (main) |
| 1 (tcp server) |
| 2 (forky) ---------(fork(2))-+
| ... | |
| N (tcp server) | |
+------------------------+ |
|
|
+-- PID 101 -------------+ # child
| fds: 0, 1, 2, 3 ... N | # fds: inherited
| threads: |
| 0 (copy of forky) | # will exec() ?
+------------------------+
调用 exec
将用一些文本 main()
替换 PID 101 过程映像(并关闭任何标记为 FD_CLOEXEC 的文件描述符)。相比之下,调用 system("whatever")
可能会产生至少两个进程:一个 (grand)child /bin/sh
和一个 (great) grandchild "whatever"。
混合使用线程、分支和共享资源很容易让自己感到困惑,尤其是当像 system()
这样的旧接口被混入其中时。慢慢来,在不需要时明确丢弃不需要的资源,一次解决一件事。