为什么像他们那样做会更好?
我不确定你的问题,也不确定这是一个更好的方法。
也许目的是为了灵活。这是我的应用程序库中的一个示例:
当我将数据属性声明为 ostream 时
class T431_t
{
// ...
std::ostream* m_so;
// ...
我可以简单地使用该属性将报告传递到“where-m_so-points”。在这个应用程序中,有几个使用 *mso
inline void reportProgress()
{
// ...
*m_so << " m_blk = " << m_blk
<< " m_N = 0x" << std::setfill('0') << std::hex << std::setw(16) << m_N
<< " " << std::dec << std::setfill(' ') << std::setw(3) << durationSec
<< "." << std::dec << std::setfill('0') << std::setw(3) << durationMSec
<< " sec (" << std::dec << std::setfill(' ') << std::setw(14)
<< digiComma(m_N) << ")" << std::endl;
// ...
}
请注意,在类构造函数(ctor)中,m_so 有一个默认赋值给 std::cout。
T431_t(uint64_t maxDuration = MaxSingleCoreMS) :
// ..
m_so (&std::cout), // ctor init - default
// ..
{
// ...
当用户选择双线程处理选项时,这是一个命令行选项,通过使用桌面的两个处理器在大约 1/2 的时间内执行应用程序,如果我允许报告可能会变得难以阅读两个独立的输出流交织在一起(在用户屏幕上)。因此,在线程 2 运行的对象实例中,m_so 被设置了一些不同的东西。
以下数据属性捕获并保存线程 2 输出以供以后流式传输到 std::cout。
std::stringstream m_ssMagic; // dual threads use separate out streams
线程 2 启动,线程将其设置为私有 m_so:
void exec2b () // thread 2 entry
{
m_now = Clock_t::now();
m_so = &m_ssMagic; // m_so points to m_ssMagic
// ...
m_ssMagic << " execDuration = " << m_ssDuration.str()
<< " (b) " << std::endl;
} // exec2b (void)
虽然线程 1 使用 std::cout,线程 2 使用 m_ssMagic,但“main”(线程 0)只是等待连接。
连接协调线程完成,通常大约在同一时间。 Main(线程 0)然后 cout 的 m_ssMagic 内容。
//...
// main thread context:
case 2: // one parameter: 2 threads each runs 1/2 of tests
{ // use two new instances
T431_t t431a(MaxDualCoreMS); // lower test sequence
T431_t t431b(MaxDualCoreMS); // upper test sequence
// 2 additional threads started here
std::thread tA (&T431_t::exec2a, &t431a);
std::thread tB (&T431_t::exec2b, &t431b);
// 2 join's - thread main (0) waits for each to complete
tA.join();
tB.join();
// tA outputs directly to std::cout
// tB captured output to T431_t::m_ssMagic.
// both thread 1 and 2 have completed, so ok to:
std::cout << t431b.ssMagicShow() << std::endl;
retVal = 0;
} break;
为了完整,这里是
std::string ssMagicShow() { return (m_ssMagic.str()); }
总结
我先写了单线程应用程序。完成这项工作后,我寻找了一种“简单”的方式来利用我桌面上的第二个内核。
作为我第一次重构的一部分,我 a) 添加了初始化为 &std::cout 的“std::ostream m_so”,并且 b) 找到了 std::cout 的所有用途。其中大部分我只是用“*m_so”替换。然后我 c) 确认我没有破坏单线程解决方案。很简单,第一次尝试就成功了。
随后的努力实现了命令行“双线程”选项。
我认为,如果预算允许,这种方法将适用于我的下一个桌面。
从 OOP 的角度来看,这项工作是有效的,因为 std::ostream 位于 std::cout 和 std::stringstream 的类层次结构中。因此
"std::cout is-a std::ostream",
和
"std::stringstream is-a std::ostream".
因此 m_so 可以指向任一派生类的实例,并为任一目的地提供虚拟方法“ostream-access”。