【问题标题】:Occasional SEG FAULT when ofstream goes out of scope当 ofstream 超出范围时偶尔会出现 SEG FAULT
【发布时间】:2012-09-14 15:33:15
【问题描述】:

当 std::ofstream 超出范围时,我很少遇到段错误问题。我的 Logger.h 中有以下结构:

        struct LogRequest
        {
            std::string line;
            std::string prefix;
        };

        struct FileInfo
        {
            std::string name;
            std::ofstream ofs;
            int lines;
            std::string ToString()
            {
                return (name + " exists");
        };

在 Logger.cpp 中,我有以下功能:

void Logger::Log(const std::string line, std::string prefix)
{
    pthread_mutex_lock(&mutex);
        if (file_map.find(prefix) == file_map.end())
        {
            OpenLogFile(prefix);
        }

        LogRequest* request = new LogRequest;
        request->line = line;
        request->prefix = prefix;
        message_queue.push_back(request);
    pthread_mutex_unlock(&mutex);
}

void Logger::OpenLogFile(const std::string& prefix)
{
    //get timestamp to use
    char timestamp[15];
    time_t now;
    time(&now);
    struct tm* current = localtime(&now);
    sprintf(timestamp, "%02u%02u%04u_%02u%02u%02u", (current->tm_mon+1),
        current->tm_mday,(1900 + current->tm_year), current->tm_hour,
        current->tm_min, current->tm_sec);

    FileInfo* info = new FileInfo;
    info->name = "logs/" + prefix + ".log_" + timestamp;
    info->ofs.open(info->name.c_str(), std::ios::out);
    info->lines = 0;

    file_map[prefix] = info;
}

void Logger::CloseLogFile(const std::string& prefix)
{
    delete file_map[prefix];
}

在 Logger.cpp 的一个线程中,我有...

void Logger::WriteToFile()
{
    std::map<std::string, FileInfo* >::iterator it;

    while(run)
    {
        char timestamp[16];
        time_t now;
        time(&now);
        struct tm* current = localtime(&now);
        sprintf(timestamp, "%02u%02u%04u|%02u%02u%02u|", (current->tm_mon+1),
            current->tm_mday,(1900 + current->tm_year), current->tm_hour,
            current->tm_min, current->tm_sec);

        pthread_mutex_lock(&mutex);
            for(it=file_map.begin(); it != file_map.end(); ++it)
            {
                if(it->second->lines > MAX_LINES)
                {
                    CloseLogFile(it->first);
                    OpenLogFile(it->first);
                }
                else
                {
                    int written = 0;

                    while(!message_queue.empty() && written < MESSAGES_PER_WRITE)
                    {
                        LogRequest* request = message_queue.front();
                        message_queue.pop_front();

                        std::string line(timestamp, 16);
                        line.append(request->line);

                        FileInfo* info = file_map[request->prefix];
                        info->ofs << line << std::endl;
                        info->lines++;
                        written++;
                        delete request;
                    }
                }
            }
        pthread_mutex_unlock(&mutex);

        usleep(1000);
    }
}

我遇到的问题是,当我尝试CloseLogFile 时,有时会在 FileInfo 中的 std::ofstream ofs 的析构函数中引发段错误。它可以工作很多次。甚至在 SEG 故障发生之前(通过各种 cout 语句)我已经确认 std::ofstream 是好的,没有失败,没有达到 eof,而且还不错。我还确认了 file_map[prefix] 存在,并且通过输出 FileInfo 的 ToString() 也存在。这些都是在 CloseLogFile 中删除之前检查的。

我的问题是关于 SEG FAULT 的原因。

此外,当行输出到 WriteToFile() 中的 ofstream 时,如果我删除 LogRequest 对象是否可以。例如,info-&gt;ofs &lt;&lt; line &lt;&lt; std::endl; 行中到底发生了什么?

【问题讨论】:

  • 双重删除?您没有从 file_map 中取出条目,因此您可能会关闭文件然后再次关闭它,这会导致析构函数或释放器崩溃,或者写入它并且因为条目仍然存在,它会'不要在写入时重新打开并崩溃,因为缓冲区不再存在。
  • @JanHudec 如果您在 WriteToFile 中看到,我会立即在互斥锁内打开新的日志文件。还会出现双重删除吗?我怎样才能事先看到 ToString 打印语句?

标签: c++ segmentation-fault ofstream


【解决方案1】:

看起来您的 sprintf(timestamp...) 调用被一个字符(null)覆盖,这将导致未定义的行为。可能是也可能不是您的主要问题,因为它在线程堆栈上,而您的 ofs 在堆上......

【讨论】:

  • null 写在哪里?即使我不写\n,sprintf 也会加一个吗?
  • 哇,可能就是这样......我想知道我是怎么错过的。这可以解释为什么它只是偶尔出现段错误,因为时间戳之后的字节大多总是空字符,偶尔会被覆盖。你知道是否有办法检查它是否是解决方案?我不知道如何测试它而不只是运行一段时间,如果它有效,假设它是固定的。
  • 很难证明没有问题...如果您使用的是 linux,如果您曾经使用过 valgrind,您可能会考虑通过它运行它。寻找此类东西的好工具...
  • 我已经有一段时间没有看到这个问题了。感谢您的帮助。我很确定这与此有关。
猜你喜欢
  • 1970-01-01
  • 2020-09-04
  • 1970-01-01
  • 2018-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-13
相关资源
最近更新 更多