20

我正在编写一个阻止来自两个输入的应用程序istreams

从任何一个读取istream都是同步(阻塞)调用,因此,我决定创建两个Boost::threads 来进行读取。

这些线程中的任何一个都可以到达“结束”(基于接收到的一些输入),一旦到达“结束”,两个输入流都会停止接收。不幸的是,我不知道哪个会这样做。

因此,我不能join()同时处理两个线程,因为只有一个线程(无法预先确定哪个线程)将实际返回(解除阻塞)。

我必须以某种方式强制对方退出,但它在等待输入时被阻塞,所以它不能自己决定是时候返回(条件变量或其他)。

他们是一种方法吗:

  • 向 boost::thread 发送信号,或
  • 强制一个istream“失败”,或
  • 杀死一个 Boost::thread?

笔记:

  • 其中之一istreamscin
  • 我正在尝试重新启动该过程,因此我无法以禁止重置输入流的方式关闭它们。

编辑:

  • 我确实知道何时到达“结束”,并且我确实知道哪个线程已成功完成,哪些需要被杀死。这是我需要弄清楚的杀戮(或从 istream 读取的不同策略)。
  • 我需要两个线程正确退出和清理:(

谢谢!

4

9 回答 9

4

我不认为有办法跨平台,但 pthread_cancel 应该是你正在寻找的。使用 boost 线程,您可以从线程中获取native_handle,并在其上调用 pthread_cancel。

此外,更好的方法可能是在多个文件上使用与 select 调用等效的 boost asio 。这样一个线程将被阻塞等待输入,但它可能来自任一输入流。不过,我不知道用 iostreams 做这样的事情有多容易。

于 2008-11-07T17:11:21.810 回答
4

就在这里!

boost::thread::terminate()将按照您的规格完成工作。

它将导致目标线程抛出异常。假设它未被捕获,堆栈将正确展开,破坏所有资源并终止线程执行。

终止不是即时的。(无论如何,那个时候错误的线程正在运行。)

它发生在预定义的条件下 - 对您来说最方便的可能是在调用时boost::this_thread::sleep();,您可以让该线程定期执行此操作。

于 2010-12-06T04:37:47.387 回答
4

如果 boost 线程阻塞了 i/o 操作(例如cin>>whatever),boost::thread::terminate()则不会终止该线程。 cini/o 不是有效的终止点。捕获 22。

于 2011-11-08T18:26:57.900 回答
1

在 linux 上,我使用 pthread_signal(SIGUSR1),因为它会中断阻塞 IO。我在移植代码时发现 Windows 上没有这样的调用。在套接字读取调用中只有一个已弃用的。在 Windows 中,您必须明确定义一个会中断您的阻塞调用的事件。所以没有这样的东西(AFAIK)作为中断阻塞 IO 的通用方法。

boost.thread 设计通过管理良好识别的中断点来处理这个问题。我不太了解 boost.asio,而且您似乎也不想依赖它。如果您不想重构以使用非阻塞范式,您可以做的是在非阻塞(轮询)和阻塞 IO 之间使用一些东西。那就是做类似(伪代码?)的事情:

while(!stopped && !interrupted)
{
    io.blockingCall(timeout);
    if(!stopped && !interrupted)
    {
        doSomething();
    }
}

然后你打断你的两个线程并加入它们......

也许在您的情况下更简单?如果您有一个知道一个线程已结束的主线程,您只需要关闭另一个线程的 IO 吗?

编辑:顺便说一句,我对您拥有的最终解决方案感兴趣...

于 2009-07-15T15:06:03.107 回答
1

我自己也遇到了类似的问题,并且已经找到了这个解决方案,这个问题的其他一些读者可能会觉得这很有用:

假设您正在使用带有 wait() 命令的条件变量,您必须知道在 Boost 中,wait() 语句是一个自然的中断点。因此,只需在带有等待语句的代码周围放置一个 try/catch 块,并允许函数在您的 catch 块中正常终止。

现在,假设您有一个带有线程指针的容器,迭代您的线程指针并在每个线程上调用 interrupt(),然后调用 join()。

现在您的所有线程都将正常终止,并且任何与 Boost 相关的内存清理工作都应该干净利落。

于 2012-08-20T22:31:23.933 回答
0

而不是试图杀死你的线程,你总是可以尝试加入线程,如果失败,你加入另一个线程。(假设您将始终能够加入您的两个线程中的至少一个)。

在 boost:thread 中,您正在寻找timed_join函数。

但是,如果您想查看正确的答案,那就是使用带定时等待的非阻塞 io。让你得到同步io的流结构,异步io的非阻塞。

您谈论从 istream 读取,但 istream 只是一个接口。对于标准输入,您只需关闭标准输入文件描述符即可中断读取。至于另一个,这取决于你从哪里阅读......

于 2008-11-07T17:14:46.140 回答
0

在 Windows 下,使用 QueueUserAPC 对引发异常的 proc 进行排队。这种方法对我来说很好。

但是:我刚刚发现 boost 互斥锁等在 win32 上不是“可提醒的”,因此 QueueUserAPC 无法中断它们。

于 2008-11-07T18:27:09.363 回答
0

似乎线程并没有以简单的方式帮助您做您想做的事。如果您不喜欢 Boost.Asio,请考虑使用select().

这个想法是获取两个文件描述符并select()用来告诉您其中哪些有可用的输入。的文件描述符cin通常是STDIN_FILENO; 如何获得另一个取决于您的具体情况(如果它是一个文件,则只是open()它而不是 using ifstream)。

在循环中调用select()以找出要读取的输入,当您想停止时,只需跳出循环即可。

于 2009-08-08T13:32:09.427 回答
0

很晚了,但是在 Windows 中(对于那些记住这些事情的人来说,它是 VMS 或 RSX 之类的前身),我会使用 ReadFileEx 之类的东西,它带有一个完成例程,在完成时发出信号,如果需要提前取消读取,则使用 CancelIO。

Linux/BSD 有一个完全不同的底层 API,它不够灵活。使用 pthread_kill 发送信号对我有用,这将停止读取/打开操作。

恕我直言,值得为每个平台在该区域实施不同的代码。

于 2013-02-15T22:58:40.230 回答