[英]Memory Corruption on c++ multithreaded application
我正在开发一个多线程C ++应用程序,并开发了用于记录的模块。 日志记录模块是一个静态类,我使用Logger :: Log(字符串文件,字符串消息)进行调用,该类使用pair<string*,string*>
填充静态队列。队列本身是一个queue<<pair<string*,string*>*>
。 就像我试图避免垃圾回收一样,所有内容都保存为指针,并认为指针变量需要特定的删除才能释放内存。
现在,当线程之一想要记录某些内容时,它将调用Log方法,该方法又追加到队列的末尾。
另一个线程遍历队列,弹出项目并将其写入指定的文件。
由于某些原因,写入文件的某些文本已损坏,因为我丢失了部分开头或消息末尾。
例如,如果我在Log方法内部调用Log(“ file”,“这是我的消息”),则我要附加一个时间戳,并创建一个新字符串,因为我认为原始字符串可能会被覆盖,但是仍然会发生。 问题在于,在某些情况下,写入文件的是时间戳记,加上消息的末尾。
这是Logger类的完整代码:
#include "Logger.h"
queue<pair<string*, string*>*> Logger::messages;
boost::mutex Logger::loggerLock;
void Logger::CleanOldFiles(vector<string> files){
for (vector<string>::iterator it = files.begin(); it != files.end(); ++it) {
string filePath = boost::filesystem::current_path().string() + "\\" + *it;
int result = remove(filePath.c_str());
}
}
void Logger::Init() {
Logger::messages = queue<pair<string*, string*>*>();
boost::thread workerThread(Logger::Process);
//workerThread.start_thread();
}
void Logger::RawLog(string file, string message) {
loggerLock.lock();
string *f = new string(file);
string *m = new string(message + "\n");
messages.push(new pair<string*, string*>(f, m));
loggerLock.unlock();
}
void Logger::Log(string file, string message) {
loggerLock.lock();
string *f = new string(file);
string *m = new string(Functions::CurrentTime() + " (" + boost::lexical_cast<string>(boost::this_thread::get_id()) + "): " + message.c_str() + "\n");
messages.push(new pair<string*, string*>(f, m));
loggerLock.unlock();
}
void Logger::Process() {
while (true) {
if (Logger::messages.size() == 0) {
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
continue;
}
loggerLock.lock();
pair<string*, string*> *entry = messages.front();
messages.pop();
loggerLock.unlock();
ofstream file(boost::filesystem::current_path().string() + "\\" + *(entry->first), ofstream::binary | ofstream::app);
file.write(entry->second->c_str(), entry->second->length());
file.close();
delete entry->first;
delete entry->second;
delete entry;
//cout << entry->second;
}
}
我希望我已经足够清楚了...
我不明白为什么会这样,有人可以给我一些如何避免这种情况的提示吗?
提前致谢。
必须将Logger::Log
设置为MT安全的,否则您将获得两个或多个线程尝试同时记录某些内容。 使其成为MT安全的最简单方法是mutex
。
if (Logger::messages.size() == 0) {
由于messages
不是线程安全的,因此如果不持有锁,则不能在其上调用任何函数。 此外,您仍然缺少对string*
的delete
调用。
您总是可以这样做:
void Logger::Process()
{
while (true)
{
loggerLock.lock();
if (Logger::messages.size() == 0)
break;
loggerLock.unlock();
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
}
pair<string*, string*> *entry = messages.front();
messages.pop();
loggerLock.unlock();
ofstream file(boost::filesystem::current_path().string() + "\\" +
*(entry->first), ofstream::binary | ofstream::app);
file.write(entry->second->c_str(), entry->second->length());
delete entry->first;
delete entry->second;
file.close();
}
但是,以供将来参考:
1)不要以这种方式使用指针。 只需使用成对的字符串队列即可。 指针什么都不买。
2)使用一些理智的同步机制,例如条件变量。 不要将sleep
用于同步。
3)使用范围锁和RAII,这样您就不会忘记解锁。
对于可能为所有人提供帮助的工作,我深表歉意,但我更正了此问题。 这实际上不是内存损坏问题,我的假设使我寻找了没有问题的东西。
问题出在调用线程上,而在我创建日志字符串的表单上。 我用错误的方式串联了字符串...该死的其他编程语言;)
我正在做诸如Logger :: Log(“ Message:” + integerVariable)之类的事情,这实际上是在将字符串向右移动(至少我认为那是在做什么)。 当我将所有这些变量都转换为字符串时,一切开始起作用。 谢谢您的帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.