在Rust中,一个异常终止了当前线程,但没有返回到主线程。我们被告知的解决方案是使用join
。然而,这阻塞了当前正在执行的线程。因此,如果我的主线程产生了2个线程,我不能同时加入它们,并立即返回一个异常。
let jh1 = thread::spawn(|| { println!("thread 1"); sleep(1000000); };
let jh2 = thread::spawn(|| { panic!("thread 2") };
在上面的例子中,如果我先在线程1上加入,然后在线程2上加入,我将在收到来自任何一个线程的死机之前等待1
虽然在某些情况下我希望实现当前的行为,但我的目标是默认使用Go语言的行为,这样我就可以生成一个线程,让它在该线程上发生异常,然后立即结束主线程(Go语言规范中还记录了一个protect
函数,因此在Go语言中实现Rust行为很容易)。
3条答案
按热度按时间r1zhe5dt1#
针对Rust 1.10+进行了更新,请参阅修订历史记录以了解以前版本的答案
说得对,在go中主线程没有被解开,程序只是崩溃了,但是报告了最初的死机。这实际上是我想要的行为(尽管理想的情况是所有地方的资源都得到了适当的清理)。
这可以通过最近稳定的
std::panic::set_hook()
函数来实现,通过它,你可以设置一个钩子,打印出异常信息,然后退出整个进程,类似于:尝试注解掉
set_hook()
调用,您将看到println!()
行得到执行。但是,由于使用了
process::exit()
,这种方法不允许释放其他线程分配的资源,事实上,我不确定Go语言运行时是否允许这样做;则它很可能使用与中止该过程相同的方法。nlejzf6q2#
我试图强迫我的代码在任何线程出现异常时停止处理。唯一不使用不稳定特性的或多或少明确的解决方案是使用在某个结构上实现的
Drop
trait。这可能会导致资源泄漏,但在我的场景中我可以接受。无论
b = PoisonPill
如何离开它的作用域,无论是正常的还是在panic!
之后,它的Drop
方法都会生效。您可以使用thread::panicking
来区分调用者是否惊慌失措,并采取一些措施-在我的例子中是终止进程。czfnxgou3#
看起来像退出整个过程中的恐慌在任何线程现在( rust 1.62)一样简单,添加到您的货物.toml:
线程中的死机如下所示,退出代码为134: