简体   繁体   English

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

[英]Memory Corruption on c++ multithreaded application

I am developing a multithreaded C++ application, and developed a module for logging. 我正在开发一个多线程C ++应用程序,并开发了用于记录的模块。 The logging module is a static class, which I call using Logger::Log(string file, string message), that fills a static queue with a pair<string*,string*> The queue itself is a queue<<pair<string*,string*>*> . 日志记录模块是一个静态类,我使用Logger :: Log(字符串文件,字符串消息)进行调用,该类使用pair<string*,string*>填充静态队列。队列本身是一个queue<<pair<string*,string*>*> Everything is saved as a pointer, as I was trying to avoid garbage collection, and believe pointer variables need specific delete to free the memory. 就像我试图避免垃圾回收一样,所有内容都保存为指针,并认为指针变量需要特定的删除才能释放内存。

Now, when one of the threads wants to log something, it calls the Log method, which in turn appends to the end of the queue. 现在,当线程之一想要记录某些内容时,它将调用Log方法,该方法又追加到队列的末尾。

Another thread runs through the queue, pops items and writes them to the designated file. 另一个线程遍历队列,弹出项目并将其写入指定的文件。

For some reason, some of the text being written to the file is corrupted, as I am losing part of the begginning or the end of the message. 由于某些原因,写入文件的某些文本已损坏,因为我丢失了部分开头或消息末尾。

For example, if I call Log("file", "this is my message"), inside the Log method I am prepending a timestamp, and creating a new string, because I thought the original string might be overwritten, but it still happens. 例如,如果我在Log方法内部调用Log(“ file”,“这是我的消息”),则我要附加一个时间戳,并创建一个新字符串,因为我认为原始字符串可能会被覆盖,但是仍然会发生。 The problem is that in some situations, what is being written to the file is the timestamp, plus only the end of the message. 问题在于,在某些情况下,写入文件的是时间戳记,加上消息的末尾。

This is the full code of the Logger class: 这是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;
    }
}

I hope I made myself clear enough... 我希望我已经足够清楚了...

I do not understand why this is happening, can anyone give me some hints on how to avoid this? 我不明白为什么会这样,有人可以给我一些如何避免这种情况的提示吗?

Thanks in advance. 提前致谢。

The Logger::Log must be made MT-safe, otherwise you can get two or more threads trying to log something simultaneously. 必须Logger::Log设置为MT安全的,否则您将获得两个或多个线程尝试同时记录某些内容。 A simplest way to make it MT-safe is a mutex . 使其成为MT安全的最简单方法是mutex

std::queue is not thread-safe. std :: queue不是线程安全的。 You need to lock access to all the shared objects or to use thread-safe queue implementation like TBB provides . 您需要锁定对所有共享对象的访问,或者使用TBB 提供的线程安全队列实现。

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

Because messages isn't thread safe, you can't call any functions on it when you don't hold the lock. 由于messages不是线程安全的,因此如果不持有锁,则不能在其上调用任何函数。 Also, you are still missing delete calls for the string* s. 此外,您仍然缺少对string*delete调用。

You can always just do this: 您总是可以这样做:

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();
}

However, for future reference: 但是,以供将来参考:

1) Don't use pointers this way. 1)不要以这种方式使用指针。 Just use a queue of pairs of strings. 只需使用成对的字符串队列即可。 The pointers don't buy you anything. 指针什么都不买。

2) Use some sane synchronization mechanism like a condition variable. 2)使用一些理智的同步机制,例如条件变量。 Don't use sleep for synchronization. 不要将sleep用于同步。

3) Use scoped locks and RAII so you don't forget an unlock. 3)使用范围锁和RAII,这样您就不会忘记解锁。

I apologize for the work I might have caused for all trying to help me, but I corrected the issue. 对于可能为所有人提供帮助的工作,我深表歉意,但我更正了此问题。 This was actually no memory corruption issue, and my assumption made me search for something where there was no problem. 这实际上不是内存损坏问题,我的假设使我寻找了没有问题的东西。

The issue was on the calling threads, and on the form I was creating the log strings. 问题出在调用线程上,而在我创建日志字符串的表单上。 I was concatenating strings in the wrong way...damn those other programming languages ;) 我用错误的方式串联了字符串...该死的其他编程语言;)

I was doing something such as Logger::Log("Message: " + integerVariable), which is fact was shifting the string to the right (at least I believe that was what it was doing). 我正在做诸如Logger :: Log(“ Message:” + integerVariable)之类的事情,这实际上是在将字符串向右移动(至少我认为那是在做什么)。 When I casted all those variables to strings, everything started working. 当我将所有这些变量都转换为字符串时,一切开始起作用。 Thank you for all your help anyway. 谢谢您的帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM