C++ 11多线程并发模式下实现带锁的std::cout,并发输
2023-09-13 本文已影响0人
FredricZhu
本例本意是模拟一个简单的barrier程序。就是使用线程组的join功能实现栅栏。但是在多线程输出的过程中,因为抢占控制台输出资源,会导致每个 operator<< 后面的输出被截断。相当于每次调用operator <<,是一次没有进行同步的写控制台操作,就会乱序。
然后谷歌了一下解决方案,可以继承一个std::stringstream,在继承类的析构函数中加锁,一次性全部输出rdbuf,避免中间被截断的问题。
方案比较简单。代码如下,
conanfile.txt
[requires]
boost/1.72.0
[generators]
cmake
CMakeLists.txt
cmake_minimum_required(VERSION 3.3)
project(3_thread_barrier)
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig/")
set ( CMAKE_CXX_FLAGS "-pthread")
set(CMAKE_CXX_STANDARD 17)
add_definitions(-g)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
include_directories(${INCLUDE_DIRS})
LINK_DIRECTORIES(${LINK_DIRS})
file( GLOB main_file_list ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
foreach( main_file ${main_file_list} )
file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${main_file})
string(REPLACE ".cpp" "" file ${filename})
add_executable(${file} ${main_file})
target_link_libraries(${file} ${CONAN_LIBS} pthread)
endforeach( main_file ${main_file_list})
async_out.hpp
#ifndef _FREDRIC_ASYNC_OUT_HPP_
#define _FREDRIC_ASYNC_OUT_HPP_
#include <sstream>
#include <mutex>
#include <iostream>
struct AsyncOut: public std::stringstream {
static inline std::mutex cout_mutex;
~AsyncOut() {
std::lock_guard<std::mutex> lock(cout_mutex);
std::cout << rdbuf();
std::cout.flush();
}
};
#define aout AsyncOut{}
#endif
main.cpp
#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>
#include <mutex>
#include "asyc_out.hpp"
int main(int argc, char* argv[]) {
std::vector<std::thread> workers;
for(int i=0; i<10; ++i) {
workers.push_back(std::thread([i](){
aout << "Hello from thread: " << i << "!\n";
}));
}
// 每次运行 Hello from main的执行时机都不一样,充满了不确定性
// Hello from thread 还有可能被截断
// 我们希望每次的运行结果都一样
aout << "Hello from main!\n";
std::for_each(workers.begin(), workers.end(), [](std::thread& th) {
th.join();
});
return EXIT_SUCCESS;
}
注意因为本例没有用到boost和其他三方库,所以可以直接用g++编译,注意链接上thread库就可以了。不一定非要CMake和conan加持。
程序输出如下,
