我有一个多线程应用程序,它大量std::cout用于日志记录而没有任何锁定.在这种情况下,如何轻松添加锁机制以使std::cout线程安全?
我不想搜索每次出现std::cout并添加一行锁定代码.这太乏味了.
有更好的做法吗?
我有通过cout和cerr写入控制台的OpenMP线程.这当然不安全,因为输出可以交错.我可以做点什么
#pragma omp critical(cerr)
{
cerr << "my variable: " << variable << endl;
}
Run Code Online (Sandbox Code Playgroud)
如果可以用线程安全版本替换cerr会更好,类似于valgrind DRD手册中解释的方法(http://valgrind.org/docs/manual/drd-manual.html#drd-manual.effective- use)涉及从std :: ostreambuf派生一个类.理想情况下,最后我会用自己的线程cerr替换cerr,例如:
tcerr << "my variable: " << variable << endl;
Run Code Online (Sandbox Code Playgroud)
一旦遇到"endl",这样的类就可以打印到控制台.我不介意来自不同线程的行是否是交错的,但每行应仅来自一个线程.
我真的不明白C++中的所有这些流是如何工作的,它太复杂了.有没有人这样的课程或者可以告诉我如何为此目的创建这样的课程?
在多个线程中使用cout可能会导致交错输出.
所以我试图用互斥锁来保护cout.
以下代码使用std :: async启动10个后台线程.线程启动时,会打印"Started thread ...".主线程按照创建顺序迭代后台线程的未来,并在相应的线程完成时打印出"Done thread ...".
输出正确同步,但在某些线程启动后有些线程已经完成(参见下面的输出),就会出现死锁.剩下所有后台线程,主线程正在等待互斥锁.
僵局的原因是什么?
当保留打印功能或for循环的一次迭代结束时,lock_guard应解锁互斥锁,以便其中一个等待线程能够继续.
为什么所有线程都挨饿?
码
#include <future>
#include <iostream>
#include <vector>
using namespace std;
std::mutex mtx; // mutex for critical section
int print_start(int i) {
lock_guard<mutex> g(mtx);
cout << "Started thread" << i << "(" << this_thread::get_id() << ") " << endl;
return i;
}
int main() {
vector<future<int>> futures;
for (int i = 0; i < 10; ++i) {
futures.push_back(async(print_start, i));
}
//retrieve and print the value stored in the …Run Code Online (Sandbox Code Playgroud) 我试图用C++编写一个程序,以尽可能最快的方式处理大量数据包.来自标准的所有数据包应尽可能快地读取,从池中发送到一个线程进行处理,然后处理到将数据包写入标准输出的输出线程.
当您在C++中使用标准输入和输出时,建议在任何输入或输出之前调用std :: ios_base :: sync_with_stdio(false)函数.在某些环境中,这可以实现很大的加速,但是在调用之后应该避免使用标准C函数进行输入/输出.
嗯,这似乎在单个线程中完美运行.但正如我所说,我的意图是使用一个线程进行输入,一个用于输出,多个线程用于并行处理.我观察到输出有些问题.这是输出线程(非常简化):
void PacketDispatcher::thread_process_output(OutputQueue& output_queue) {
std::vector<Packet> packet_list;
while(output_queue.get(packet_list)) {
for (const auto& packet: packet_list) {
std::cout << "Packet id = " << packet.id << "\n";
}
}
std::cout.flush();
}
Run Code Online (Sandbox Code Playgroud)
如果我使用std :: endl而不是"\n",那么腐败就会减少,但是std :: endl强制刷新流,在这种情况下影响性能(并且问题没有解决,只是最小化).
这是使用std :: cout的程序中唯一的一点,但是如果我在程序开始时调用std :: ios_base :: sync_with_stdio(false),我会得到一个明显的加速,但是我的输出总是被损坏了一些办法:
Packet id = Packet id = 4
Packet id = 5
Packet id = 6
Packet id = 7
Packet id = 8
Packet id …Run Code Online (Sandbox Code Playgroud) 我知道当前没有线程的概念C++,但是本文说:
类型安全,线程安全,便携式 日志记录机制
.....
该
fprintf()函数是线程安全的,因此即使从不同的线程使用此日志,输出行也不会被加扰.
怎么样cout,cerr和clog?
我认为这个问题适用于C++中的所有类型的流类型,例如fstream和stringstream.
我理解为了避免输出混合,必须同步多个线程对cout和cerr的访问.在同时使用cout和cerr的程序中,单独锁定它们是否足够?或者同时写cout和cerr仍然不安全?
编辑说明:我知道cout和cerr在C++ 11中是"线程安全的".我的问题是,对cout的写入和对不同线程的cerr的写入是否会以两次写入cout的方式相互干扰(导致交错输入等).
我正在为游戏项目使用一些多线程代码,并且厌倦了使用cout同时对两个线程创建的stdout呕吐进行排序.我做了一些研究,在拿出"东西"之前盯着墙壁呆了一两个小时.以下代码使用SFML进行计时和线程处理.SFML互斥体只是窗口中包含的关键部分.
标题:
#include <SFML\System.hpp>
#include <iostream>
class OutputStreamHack
{
public:
OutputStreamHack();
~OutputStreamHack();
ostream& outputHijack(ostream &os);
private:
sf::Clock myRunTime;
sf::Mutex myMutex;
};
static OutputStream OUTHACK;
ostream& operator<<(ostream& os, const OutputStreamHack& inputValue);
Run Code Online (Sandbox Code Playgroud)
执行:
#include <SFML\System.hpp>
#include <iostream>
#include "OutputStreamHack.h"
using namespace std;
OutputStreamHack::OutputStreamHack()
{
myMutex.Unlock();
myRunTime.Reset();
}
OutputStreamHack::~OutputStreamHack()
{
myMutex.Unlock();
myRunTime.Reset();
}
ostream& OutputStreamHack::outputHijack(ostream &os)
{
sf::Lock lock(myMutex);
os<<"<"<<myRunTime.GetElapsedTime()<<","<<GetCurrentThreadId()<<"> "<<flush;
return os;
}
ostream& operator<<(ostream& os, const OutputStreamHack& inputValue)
{
OUTHACK.outputHijack(os);
return os;
}
Run Code Online (Sandbox Code Playgroud)
用法:
cout<<OUTHACK<<val1<<val2<<val3....<<endl;
Run Code Online (Sandbox Code Playgroud)
好的,所以它的工作方式是通过重载的插入操作符,通过将迭代器锁定在静态对象中,然后刷新缓冲区来强制线程安全.如果我正确地理解了这个过程(我主要是一个自学成才的程序员),cout会从头到尾处理其插入链的元素,在链中传递一个ostream变量,为每个元素预先添加到流中.一旦到达OUTHACK元素,就会调用重载的运算符,锁定互斥锁,并刷新流.
我已经将一些时间/线程ID调试信息添加到输出中以进行验证.到目前为止,我的测试显示此方法有效.我有几个线程用多个参数敲击cout,一切都以正确的顺序出现.
根据我在研究这个问题时所阅读的内容,cout中缺乏线程安全性似乎是人们在进入线程编程时遇到的一个非常常见的问题.我想弄清楚的是,如果我使用的技术是一个简单的问题解决方案,或者我认为我很聪明但缺少一些重要的东西.
根据我的经验,用于描述编程的聪明一词只是延迟疼痛的代码词.我在这里做些什么,或者只是在圈子里追逐糟糕的黑客?
谢谢!
我正在尝试编译一些使用线程的C++代码:
#include <iostream>
#include <thread>
void hello()
{
std::cout<<"Hello Concurrent World\n";
}
int _main(int argc, _TCHAR* argv[])
{
std::thread t(hello);
t.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译时出错:
c:\temp\app1\app1\app1.cpp(6): fatal error C1083: Cannot open
include file: 'thread': No such file or directory
~/Documents/C++ $ g++ -o thread1 thread1.cpp -D_REENTRANT -lpthread
In file included from /usr/include/c++/4.5/thread:35:0,
from thread1.cpp:2:
/usr/include/c++/4.5/bits/c++0x_warning.h:31:2: error: #error This file
requires compiler and library support for the upcoming ISO C++ standard,
C++0x. This support is currently experimental, and must be enabled …Run Code Online (Sandbox Code Playgroud) 我一直在使用多线程编码,经过一段时间的编写,我意识到如果我在不同的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 …
int main() {
thread t1([] {printer("*", 100); });
thread t2([] {printer("+", 100); });
t1.join();
t2.join();
}
void printer(string c, int num)
{
for (int i = 1; i <= num; i++)
{
cout << c;
}
cout << endl;
}
Run Code Online (Sandbox Code Playgroud)
现在这打印像****+++**我希望它在一行中打印***然后+++全部在一行中.我们不允许使用互斥锁或阻止线程访问打印机功能.代码仍然必须是多线程的.
关于如何做到这一点的任何想法?