c ++多线程应用程序的内存损坏

时间:2014-07-30 17:30:34

标签: c++ multithreading memory logging

我正在开发一个多线程C ++应用程序,并开发了一个用于记录的模块。日志记录模块是一个静态类,我使用Logger :: Log(字符串文件,字符串消息)调用,它使用pair<string*,string*>填充静态队列。队列本身是queue<<pair<string*,string*>*>。一切都保存为指针,因为我试图避免垃圾收集,并且相信指针变量需要特定的删除来释放内存。

现在,当其中一个线程想要记录某些内容时,它会调用Log方法,而该方法又会附加到队列的末尾。

另一个线程在队列中运行,弹出项目并将它们写入指定的文件。

出于某种原因,写入文件的一些文本已损坏,因为我正在丢失部分文件或邮件的结尾。

例如,如果我调用Log(“file”,“这是我的消息”),在Log方法中我会在前面添加一个时间戳,并创建一个新字符串,因为我认为原始字符串可能会被覆盖,但是它仍然发生。 问题是在某些情况下,写入文件的是时间戳,加上只有消息的结尾。

这是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;
    }
}

我希望自己足够清楚......

我不明白为什么会发生这种情况,有人能给我一些关于如何避免这种情况的提示吗?

提前致谢。

4 个答案:

答案 0 :(得分:1)

Logger::Log 必须为MT安全,否则您可以获得两个或多个线程同时尝试记录某些内容。使其成为MT安全的最简单方法是mutex

答案 1 :(得分:1)

std :: queue不是线程安全的。您需要锁定对所有共享对象的访问权限或使用TBB provides之类的线程安全队列实现。

答案 2 :(得分:0)

    if (Logger::messages.size() == 0) {

因为messages不是线程安全的,所以当你不持有锁时,你不能调用它上面的任何函数。此外,您仍然缺少对delete的{​​{1}}次来电。

你总是可以这样做:

string*

然而,供将来参考:

1)不要以这种方式使用指针。只需使用成对字符串的队列。指针不会给你买任何东西。

2)使用一些理智的同步机制,如条件变量。请勿使用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(); } 进行同步。

3)使用范围锁和RAII,这样你就不会忘记解锁。

答案 3 :(得分:0)

我为所有试图帮助我的工作道歉,但我纠正了这个问题。这实际上没有内存损坏问题,我的假设让我搜索没有问题的东西。

问题出在调用线程上,在表单上我创建了日志字符串。我以错误的方式连接字符串......该死的其他编程语言;)

我正在做一些事情,比如Logger :: Log(“Message:”+ integerVariable),这实际上是将字符串向右移动(至少我相信它就是它正在做的事情)。当我将所有这些变量转换为字符串时,一切都开始工作了。无论如何,谢谢你的帮助。