如何有效地使用 std::osyncstream 对象?

How to efficiently use the std::osyncstream objects?

提问人:digito_evo 提问时间:12/27/2022 更新时间:1/18/2023 访问量:192

问:

在 cppreference 上有一个关于如何使用类的示例代码:std::osyncstream

#include <string_view>
#include <syncstream>
#include <iostream>
#include <thread>
 
void worker(const int id, std::ostream &os) {
  std::string_view block;
  switch (id) {
    default: [[fallthrough]];
    case 0: block = "██"; break;
    case 1: block = "▓▓"; break;
    case 2: block = "▒▒"; break;
    case 3: block = "░░"; break;
  }
  for(int i = 1; i <= 50; ++i) {
    os << block << std::flush;
  }
  os << std::endl;
}
 
int main() {
  std::cout << "Synchronized output should not cause any interference:" << std::endl;
  {
    auto scout1 = std::osyncstream{std::cout};
    auto scout2 = std::osyncstream{std::cout};
    auto scout3 = std::osyncstream{std::cout};
    auto scout4 = std::osyncstream{std::cout};
    auto w1 = std::jthread{worker, 0, std::ref(scout1)};
    auto w2 = std::jthread{worker, 1, std::ref(scout2)};
    auto w3 = std::jthread{worker, 2, std::ref(scout3)};
    auto w4 = std::jthread{worker, 3, std::ref(scout4)};
  }
 
  std::cout << "\nLack of synchronization may cause some interference on output:" << std::endl;
  {
    auto w1 = std::jthread{worker, 0, std::ref(std::cout)};
    auto w2 = std::jthread{worker, 1, std::ref(std::cout)};
    auto w3 = std::jthread{worker, 2, std::ref(std::cout)};
    auto w4 = std::jthread{worker, 3, std::ref(std::cout)};
  }
}

现在我的问题很简单:为每个单独的执行线程使用这些对象的最有效(就运行时速度而言)方法是什么?在上面的示例中,它们是在调用站点构造的,然后通过引用传递给线程(顺便说一句,如何绑定到类型的对象?另一方面,在我的小程序中,我尝试在每个函数中构造一个单独的本地对象,然后写入它,这工作正常。这样我就不必通过引用函数(如上面的代码)来传递它们。std::ostream &osstd::osyncstream{std::cout}std::osyncstream{std::cout}

那么创建这些对象的规则是什么呢?我们需要创建多少个,在哪里创建?我目前有一个小程序,它同时运行两个不相关的 s,这两个 s 都按顺序调用多个函数(每个函数 8 个),这些函数尝试写入 .我需要防止文本交错。现在,这 16 个函数中的每一个都通过 .添加这些对象后,可执行文件的大小翻了一番。因此,这似乎根本不是最佳方法。我是否应该在每个函数中有一个对象,然后通过引用将其传递给按顺序运行的 8 个内部函数?std::jthreadjthreadstd::coutcoutstd::osyncstream{std::cout} << "like this\n";osyncstreamstd::osyncstreamjthread

C++ IO C++20 线程同步

评论


答:

1赞 Cubbi 1/18/2023 #1

顺便说一句,如何绑定到类型的对象?std::ostream &osstd::osyncstream{std::cout}

与对 TYPE 的任何引用绑定到表达式的方式相同BaseDerived

那么创建这些对象的规则是什么呢?我们需要创建多少个,在哪里创建?

每个单独的对象都包含一个单独的(以及每个对象保存的一堆其他状态),该状态包含一个单独的堆分配的字节缓冲区(加上几个标志和指向 cout 互斥锁的指针)。 因此,如果您总是使用临时临时 (),则可能会破坏并重新创建所有这些状态和所有这些缓冲区,这可能是不必要的。原始代码通过为每个线程分配一个线程来避免这种徒劳的工作。osyncstreamsyncbufostreamstd::osyncstream{std::cout} << "like this\n";osyncstream

评论

0赞 digito_evo 1/18/2023
所以你说为每个线程创建一个这些对象,然后将它们传递给线程是件好事吗?这就是我最终所做的,它大大减小了可执行文件的大小。