2008-11-07 48 views
20

我在写一个应用程序,它阻止来自两个istreams的输入。杀死阻塞的Boost ::线程

istream读取的是一个同步(阻塞)调用,所以我决定创建两个Boost::thread来完成读取。

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

因此,我不能在两个线程上都使用join(),因为只有一个线程(不能预先确定哪一个)会实际返回(取消阻塞)。

我必须以某种方式迫使另一个退出,但它被阻止等待输入,所以它不能自己决定是时候返回(条件变量或不是)。

是他们的一种方式之一:

  • 发送信号,一个boost ::线程,或
  • istream为 “失败”,或
  • 杀死一升压::主题?

注:

  • 其中istreams的是cin
  • 我试图重新启动的过程中,所以我不能关闭,禁止他们正在重置的方式输入流。

编辑:

  • 达到了“结束”时,我知道,我知道哪个线程已成功完成,并需要被杀害。我需要弄清楚它的杀戮(或者从一个istream中读取不同的策略)。
  • 我需要两个线程退出并清理正确:(

谢谢!

回答

4

我不认为有办法做到这一点的跨平台的,但pthread_cancel可以应该是你在找什么随着升压线程你可以从一个线程获得native_handle,并呼吁它pthread_cancel可以。

另外一个更好的办法可能是使用升压asio等于多个文件选择调用的。这样一个线程被阻塞等待输入,但它可能来自任何一个输入str EAM。但我不知道用iostreams做这种事情有多容易。

+0

幸运的是,我现在正在为linux机器开发,但更喜欢便携式版本。感谢你! – mmocny 2008-11-07 17:13:31

+0

pthread_cancel()在类似的情况下没有为我设置它,甚至不把它的取消类型设置为ASYNCHRONOUS。 – gatopeich 2011-03-21 12:24:19

0

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

提升:线程您正在寻找timed_join函数。

但是,如果您想查看正确的答案,那就是使用具有定时等待的非阻塞io。允许您获得异步io的非阻塞同步io的流结构。

你说的是读一个istream,但一个istream只是一个接口。对于标准输入,你可以忽略标准输入文件描述符来中断读取。至于另一个,它取决于您正在阅读的位置...

+0

有关如何做到这一点的任何建议?我的印象是不可能的(可以轻易地做到这一点)与cin。我已经提到我正在加入一个线程,而另一个线程则是我需要处理的。不过谢谢。 – mmocny 2008-11-07 17:19:13

0

在Windows下,使用QueueUserAPC排队引发异常的proc。这种方法适用于我。

但是:我刚刚发现boost mutex等在win32上不是“可警告的”,所以QueueUserAPC不能中断它们。

1

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

boost.thread设计通过管理良好识别的中断点来处理此问题。我不太了解boost.asio,看起来你不想依赖它。如果你不想重构使用非阻塞范例,你可以做的是在非阻塞(轮询)和阻塞IO之间使用一些东西。这是做类似的信息(伪代码):

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

然后你打断你的两个线程,并加入他们的行列......

也许正是你的情况更简单?如果你有一个知道一个线程结束的主线程,你只需要关闭另一个线程的IO呢?

编辑: 通过我感兴趣的是你的最终解决方案的方式......

0

看来,线程不帮你做,你以简单的方式想要什么。如果Boost.Asio不符合您的喜好,请考虑使用select()

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

在循环中调用select()以找出要读取哪个输入,以及何时停止,只是跳出循环。

4

是的!

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

这将导致目标线程抛出异常。假设它没有被捕获,堆栈将正确地销毁所有资源并终止线程执行。

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

它在预定义的条件下发生 - 最方便的方法是调用boost::this_thread::sleep();,您可以定期使用该线程。

4

如果升级线程在I/O操作上阻塞(例如cin>>whatever),则boost::thread::terminate()不会终止该线程。 cin I/O不是有效的终止点。抓22.

1

我也有类似的问题我自己,并已达到该解决方案,这个问题的一些其他的读者可能会发现有用:

假设你正在使用一个条件变量与等待()命令,它对于您来说知道在Boost中,wait()语句是一个自然中断点非常重要。所以,只需在wait语句的代码周围放一个try/catch块,并允许函数在catch块中正常终止。

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

现在,所有线程都将优雅地终止,任何与Boost相关的内存清理都应该干净地工作。

0

很晚了,但在Windows中(它是像VMS或RSX这样的前驱体,用于那些重播这样的事情)我会用ReadFileEx这样的完成例程来完成信号,而CancelIO如果读取需要被取消早。

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

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