同步STD cout输出多线程

k3o*_*3oy 6 c++ multithreading synchronization cout

我一直在使用多线程编码,经过一段时间的编写,我意识到如果我在不同的boost :: threads中使用std :: cout,输出将没有逻辑顺序,我正在测试的程序是就像是:

#include <boost/thread/thread.hpp>
#include <iostream>

int my01( void )
{
    std::cout << "my01" << std::endl;
    return 0;
}
/* my02, my03 and my04 are the same with different outputs*/
[...]
int main( void )
{
    boost::thread t1(&my01);
    boost::thread t2(&my02);
    boost::thread t3(&my03);
    boost::thread t4(&my04);

    while(!t1.joinable() || !t2.joinable() || !t3.joinable() || !t4.joinable());

    t1.join();
    t2.join();
    t3.join();
    t4.join();

    std::cout << "The end!" << std::endl;
    getchar();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)


输出通常就像(它改变):

my02my01
my04
my03
BLANK LINE
结束!

考虑到这个问题,我想创建一个单独的线程来管理所有输出,所以它们将按顺序排列:

MY01
MY02
my03
my04
结束!

编写此类线程或管理这些输出的最佳方法是什么?
请仔细阅读这个问题的答案:cout是同步还是线程安全的?

Ps:我使用的是Visual C++ 2010 Express,我的cpu有8个不同的内核.

感谢您的时间!

Jer*_*fin 9

首先,您可以考虑避免所有显式线程管理,而是使用std::async在任意数量的单独线程中启动任务.

其次,您不想在线程本身中执行I/O,而是要创建结果,并按顺序执行输出.这意味着线程函数只是创建了一些数据,并将其留给调用者实际写出来:

std::string process(int value) {
     std::ostringstream buffer;
     buffer << "my" << std::setfill('0') << std::setw(2) << value;
     return buffer.str();
}
Run Code Online (Sandbox Code Playgroud)

然后我们需要以异步方式启动它的四个副本:

std::vector<std::future<std::string> > results;

for (int i=0; i<4; i++)
    results.push_back(std::async(std::launch::async, process, i));
Run Code Online (Sandbox Code Playgroud)

然后我们等待结果并按顺序打印出来:

for (auto &r : results)
    std::cout << r.get() << "\n";
Run Code Online (Sandbox Code Playgroud)

我应该补充一点:我的基础是标准C++ 11 future.我相信基本的想法也应该与Boost future(标准所基于的)一起使用,但还没有测试过.一些小的调整(例如,名称)需要与Boost的期货工作(虽然因为,如前所述,该代码没有经过测试,可与标准的期货也需要一些调整,但希望能少呢).


Dim*_*ima 5

我通过编写一个薄包装器解决了这个问题,该包装器在开始写入流时锁定互斥锁,并在写入语句完成后释放它,同时刷新流。

用法:用 safe_cout 替换 std::cout。

请记住,它不支持像 std::endl 这样的花哨的 std::cout 功能。

请参阅下面的代码或从这里获取它:https : //github.com/dkorolev/felicity/blob/master/safe_ostream.h

#include <cassert>
#include <iostream>
#include <mutex>
#include <memory>

struct safe_ostream {
  struct guarded_impl {
    guarded_impl() = delete;
    guarded_impl(const guarded_impl&) = delete;
    void operator=(const guarded_impl&) = delete;
    guarded_impl(std::ostream& ostream, std::mutex& mutex) : ostream_(ostream), guard_(mutex) {
    }
    ~guarded_impl() {
      ostream_.flush();
    }
    template<typename T> void write(const T& x) {
      ostream_ << x;
    }
    std::ostream& ostream_;
    std::lock_guard<std::mutex> guard_;
  };
  struct impl {
    impl() = delete;
    void operator=(const impl&) = delete;
    impl(std::ostream& ostream, std::mutex& mutex) : unique_impl_(new guarded_impl(ostream, mutex)) {
    }
    impl(const impl& rhs) {
      assert(rhs.unique_impl_.get());
      unique_impl_.swap(rhs.unique_impl_);
    }
    template<typename T> impl& operator<<(const T& x) {
      guarded_impl* p = unique_impl_.get();
      assert(p);
      p->write(x);
      return *this;
    }
    mutable std::unique_ptr<guarded_impl> unique_impl_;
  };
  explicit safe_ostream(std::ostream& ostream) : ostream_(ostream) {
  }
  template<typename T> impl operator<<(const T& x) {
    return impl(ostream_, mutex_) << x;
  }
  std::ostream& ostream_;
  std::mutex mutex_;
};
safe_ostream safe_cout(std::cout);
safe_ostream safe_cerr(std::cerr);
Run Code Online (Sandbox Code Playgroud)

  • 迪玛,锁定是邪恶的。 (2认同)