Rust中使用nix库SIGALARM实现进程通信遇阻塞问题求助
Rust中使用nix库alarm功能实现进程间通信的问题
我尝试通过SIGALRM让两个子进程每2秒互相通信,并通过管道返回数据,但运行代码后程序一直处于等待状态,看不到预期消息。以下是我的代码:
use nix::sys::wait::wait; use nix::unistd::ForkResult::{Child, Parent}; use nix::unistd::fork; use nix::unistd::{alarm, pause}; use nix::sys::signal::*; use std::io::prelude::*; extern fn signal_handler(_: nix::libc::c_int) {} fn set_alarm(sec: i32) { alarm::set(sec.try_into().unwrap()); } fn main() { let (mut reader_2, mut writer_2) = os_pipe::pipe().unwrap(); unsafe { sigaction( Signal::SIGALRM, &SigAction::new( SigHandler::Handler(signal_handler), SaFlags::empty(), SigSet::empty()) ).unwrap(); } let pid = fork(); match pid.expect("Error during creating child") { Parent { child } => { drop(writer_2); let pid_2 = fork(); match pid_2.expect("Error creating child 2") { Parent { child } => {} Child => { let mut data: [u8;2] = [0;2]; for _ in 1..=10 { set_alarm(2); pause(); reader_2.read_exact(&mut data).unwrap(); println!("Data from C1, {}", std::str::from_utf8(&data).unwrap()); } } } } Child => { drop(reader_2); for _ in 1..=10 { pause(); println!("here"); writer_2.write("C1".as_bytes()).unwrap(); } } } wait().unwrap(); }
问题分析与修复方案
核心问题点
- 第一个子进程(C1)未设置闹钟:C1的循环中只有
pause(),从未调用set_alarm(),导致它永远阻塞等待信号,无法往管道写入数据,进而让第二个子进程(C2)读管道时阻塞。 - 父进程等待逻辑缺失:原代码只调用一次
wait(),无法保证等待两个子进程全部结束,可能导致父进程提前退出。 - alarm调用错误:nix库中
alarm是直接调用的函数,而非alarm::set()模块方法。 - 管道句柄提前释放:父进程提前
drop(writer_2)会影响C1的管道写入句柄有效性。
修正后的代码
use nix::sys::wait::waitpid; use nix::unistd::ForkResult::{Child, Parent}; use nix::unistd::{fork, Pid}; use nix::unistd::{alarm, pause}; use nix::sys::signal::*; use std::io::prelude::*; extern fn signal_handler(_: nix::libc::c_int) {} fn set_alarm(sec: u32) { alarm(sec); } fn main() { let (mut reader_2, mut writer_2) = os_pipe::pipe().unwrap(); unsafe { sigaction( Signal::SIGALRM, &SigAction::new( SigHandler::Handler(signal_handler), SaFlags::SA_RESTART, SigSet::empty()) ).unwrap(); } let pid = fork().expect("Error during creating child"); match pid { Parent { child: c1_pid } => { let pid_2 = fork().expect("Error creating child 2"); match pid_2 { Parent { child: c2_pid } => { waitpid(c1_pid, None).unwrap(); waitpid(c2_pid, None).unwrap(); } Child => { drop(writer_2); let mut data: [u8;2] = [0;2]; for _ in 1..=10 { set_alarm(2); pause(); if reader_2.read_exact(&mut data).is_ok() { println!("Data from C1: {}", std::str::from_utf8(&data).unwrap()); } } } } } Child => { drop(reader_2); for _ in 1..=10 { set_alarm(2); pause(); println!("C1 sending data..."); writer_2.write_all("C1".as_bytes()).unwrap(); writer_2.flush().unwrap(); } } } }
关键修正说明
- 给C1添加闹钟设置:确保C1每2秒被SIGALRM唤醒,执行管道写入操作。
- 修正alarm调用:使用nix库原生的
alarm()函数替代错误的alarm::set()。 - 完善父进程等待逻辑:用
waitpid分别等待两个子进程,保证所有子进程执行完毕。 - 调整管道句柄释放时机:在对应的子进程中释放不需要的管道句柄,避免父进程提前释放影响子进程。
- 添加SA_RESTART标志:让被信号中断的系统调用自动重启,提升程序稳定性。
- 使用write_all和flush:确保数据完整写入管道并刷新缓冲区,避免数据滞留。
内容的提问来源于stack exchange,提问作者danixl30 ct
相关产品推荐
相关产品推荐

