我创建了两个类。一个用于输入读取(通过 istream 对象)和解析,另一个用于处理解析器的输出。
每一种都有一个实例。
我让解析器在调用 istream::get() 的循环中运行,然后根据输入为第二个对象创建命令。然后将这些命令放在第二个对象在单独线程中处理的队列中。
现在很明显,我最终需要能够发送“退出”命令。但是问题出现了:“退出”命令也需要结束解析循环,但我找不到一种方法来指示解析器应该退出,因为它被 istream::get() 捕获。
我需要一种方法将其从该方法中唤醒,但我找不到任何...
我曾想过通过从 istream::rdbuf() 创建一个 ostream 对象来向 istream 对象(在本例中为 cin)写入某种“终止序列”。但这不起作用 - 在尝试写入缓冲区后设置了坏位。
在 StackOverflow 的另一个问题中,我看到了提到的 Boost 库的 asio 类,但我宁愿不依赖第三方库。
有没有办法从 istream::get() 唤醒线程 - 即有没有办法从程序中写入 istream 缓冲区(可能假设它实际上是 cin)?
另一种方法是杀死我认为可以接受的线程,因为在该特定位置不需要清理。但这怎么能做到呢?(我依赖于 POSIX 线程实现)
2 回答
这有可能在.NET中实现吗?- 如果是这样,请查看Reactive Framework。它提供了一种非常优雅的方式来处理流,尤其是即时取消它们。
- 最重要的是,您可以获得一个非常可扩展的 Linq 扩展库,用于各种东西,如缓冲、记忆、Zip 等。
我们经常使用它来转换(和解析)流数据的建模。
Reative 团队的 Jeff 在这里有几个关于Streaming 和 Reative的不错的博客:
您将不得不依赖标准 iostream 类以外的东西,因为它们不提供select()
-style 行为。
此外,使用 POSIX 杀死线程是不可能的(并且在 Windows 中完全被破坏)。您可以通过 发出取消请求pthread_cancel()
,但在您的情况下,它可能会卡在不可取消的系统调用中。您特别感兴趣的,read()
可能会或可能不会被取消,具体取决于环境。至少有一个环境表明可能会出现取消点read()
,尽管不可否认它是 Windows POSIX 层。此外,Mac OS X,以及最近的Leopard 10.5.1,在read()
可取消性方面的实现有缺陷。
一旦越过了这个障碍,您还必须考虑C++ 析构函数和 pthread_cancel 之间的不安关系。并非所有环境都保证会调用析构函数,因此在 C++ 代码中使用 pthread_cancel 时必须格外小心。
简而言之,对于可中断的 I/O,使用低级 I/O 和select()
:一个 fd 用于 I/O,第二个 fd(由 创建pipe()
)用于信令。或者,如果你够勇敢,可以使用AIO,但最好使用高级接口,例如Boost.Asio。