0

I'm trying to get a parent process and a child process to communicate with each other using a Tokio UnixStream. Problem is that for some reason the child is unable to read whatever the parent writes to the socket (and presumably the other way around.

The function I have is similar to the following

    pub async fn run() -> Result<(), Error> {
        let mut socks = UnixStream::pair()?;

        match fork() {
            Ok(ForkResult::Parent { .. }) => {
                socks.0.write_u32(31337).await?;
                Ok(())
            }

            Ok(ForkResult::Child) => {
                eprintln!("Reading from master");
                let msg = socks.1.read_u32().await?;
                eprintln!("Read from master {}", msg);
                Ok(())
            }
            Err(_) => Err(Error),
        }
    }

The socket doesn't get closed, otherwise I'd get an immediate error trying to read from socks.1. If I move the read into the parent process it works as expected. The first line Reading from master gets printed, but the second line never gets called.

I cannot change the communication paradigm, since I'll be using execve to start another binary that expects to be talking to a socketpair.

Any idea what I'm doing wrong here? Is it something to do with the async/await statemachine that's generated from the async function?

4

1 回答 1

1

当你调用fork()系统调用时:

子进程是使用单个线程创建的——调用 fork() 的线程。

tokio 中的默认执行器是线程池执行器。子进程只会获得池中的一个线程,因此无法正常工作。

我发现我可以通过将线程池设置为仅包含一个线程来使您的程序工作,如下所示:

use tokio::prelude::*;
use tokio::net::UnixStream;
use nix::unistd::{fork, ForkResult};
use nix::sys::wait;
use std::io::Error;
use std::io::ErrorKind;
use wait::wait;

// Limit to 1 thread
#[tokio::main(core_threads = 1)]
async fn main() -> Result<(), Error> {
    let mut socks = UnixStream::pair()?;

    match fork() {
        Ok(ForkResult::Parent { .. }) => {
            eprintln!("Writing!");
            socks.0.write_u32(31337).await?;
            eprintln!("Written!");
            wait().unwrap();
            Ok(())
        }

        Ok(ForkResult::Child) => {
            eprintln!("Reading from master");
            let msg = socks.1.read_u32().await?;
            eprintln!("Read from master {}", msg);
            Ok(())
        }

        Err(_) => Err(Error::new(ErrorKind::Other, "oh no!")),
    }
}

我必须做的另一个改变是通过调用强制父母等待孩子完成wait()- 这也是你可能不想在真正的异步程序中做的事情。

我读过的大多数建议是,如果您需要从线程程序中分叉,请在创建任何线程之前执行此操作,或者exec_ve()在分叉后立即调用子程序(无论如何,这都是您打算做的)。

于 2020-03-14T22:43:53.030 回答