2017-12-05 28 views
-3

コンソールにメッセージを出力する簡単なスレッドセーフロガーを試してみました。マルチスレッドアプリケーションでstringstreamを使用したセグメンテーションフォルト(コアダンプ)

// Test function for check logger. It is work 
void test(double& diff) 
{ 
    std::vector<double> result; 
    for(int counter = 0; counter < 100000; ++counter) 
    { 
    result.push_back(clock()); 

    std::string text = "counter = "; 
    text.append(std::to_string(counter)); 
    LOG_MESSAGE(text); //<-- Correct log.. 
    } 
    diff = clock() - result.front(); 

} 

int main(int argc, char** argv) 
{ 
    double time2; 
    double time1; 
    std::vector<double> timerResult; 
    std::vector<std::thread> threadVector; 

    time1 = clock(); 
    for(int i = 0; i < 5; ++i) //<-- Create 5 thread of test function 
    { 
    timerResult.push_back(0); 
    threadVector.push_back(std::thread(test, std::ref(timerResult[i]))); 
    } 
    for(std::thread& t : threadVector) 
    t.join(); 
    time2 = clock(); //<-- Threads is finished 

    double res = 0; 
    for(double tRes : timerResult) 
    res += tRes; 
    res = res/static_cast<double>(CLOCKS_PER_SEC); 

    std::string message; //<-- Generate final message 
    message.append("Timer: ") 
     .append(std::to_string((time2 - time1)/(double)CLOCKS_PER_SEC)) 
     .append(" - thread timer: ") 
     .append(std::to_string(res)); 

    LOG_MESSAGE(message); //<-- Crash inside!!  

    return 0; 
} 

ロガーはスレッドで正常に動作します。しかし、私は(構造ログメッセージの機能で)のstd :: ostringstreamのデストラクタでSIGSEGV信号を呼び出すmain()関数にログインしようとすると:

static Logger::Core logger; //<--Global Logger variable 

#define LOG_MESSAGE(TEXT) logger.addNoteInLog(TEXT) //<-- Define for log message 

void Core::addNoteInLog(const Message &message) //<-- threadsafe log function 
{ 
    std::string text; 
    message.generateString(text); //<-- [Crash here] generate log message 
    g_lock.lock(); 
    std::cout << text; 
    g_lock.unlock(); 
} 

void Message::generateString(std::string& text) const 
{ 
    text.clear(); 
    tm *ltm = localtime(&mDate); 

    std::ostringstream data; //<-- [Crash here] function is finished, but cannot destruct object. 
    data << 1900 + ltm->tm_year << "/" 
     << 1 + ltm->tm_mon << "/" 
     << ltm->tm_mday << "\t"; 
    data << "[INF] - "; 
    data << std::this_thread::get_id() << " - " 
     << mMessage << "\n"; 

    text = data.str(); 
} 

が、私はスレッドでロガーが仕事である理由を理解しないが、メインで()関数がクラッシュしました。排除法を用いて、私は、エラーが発生したときに判明:

  • Iは、5(またはそれ以上)を使用する場合generateString中にstringstream又はostringstreamまたは文字列を使用すると、試験機能が
  • 空でない場合
  • をスレッド.append()(最後のケースでは、同じ場所のstd :: stringデストラクタのアプリケーションクラッシュ)

QtCreaterのデバッガは何ですか? UbuntuのOSで

ビルド、gccのバージョン5.4.0、コンパイルフラグ:-std=c++17 -pthread -Wall

Thisがエラーと私のgitリポジトリです。

+0

FYIドキュメントは 'localtime'はスレッドセーフでない場合があることに注意してください。ロック内の 'generateString'への呼び出しを移動するとどうなりますか? –

+0

セグメンテーションフォルトが青色から出ない。あなたはデバッガのスタックトレースを調べましたか?どこから来たのでしょうか? – user0042

+1

あなたのベクトルをチェックしますか?ベクトルが大きくなるとベクトルが完全に再割り当てされるので、スレッドがゴミを指している可能性があることを覚えておいてください。予備を使用してベクトルのサイズを事前に設定すると、ヘルプになる可能性があります。 –

答えて

0

問題を解決しました。 push_backを5回呼び出した後にメモリの再割り当てがtimerResultに行われ、ref(timerResult[i])での参照が正しくないため、コメントで述べたように、threadVector.push_back(std::thread(test, std::ref(timerResult[i])));の行が正しくありません。

正しいコード:

int main(int argc, char** argv) 
    { 
     double time2; 
     double time1; 
     std::vector<double> timerResult (5); //<-- Create filling of vector 
     std::vector<std::thread> threadVector; 

     time1 = clock(); 
     for(int i = 0; i < 5; ++i) 
     { 
     //timerResult.push_back(0); //<-- incorrect filling of vector 
     threadVector.push_back(std::thread(test, std::ref(timerResult[i]))); 
     } 
     for(std::thread& t : threadVector) 
     t.join(); 
     time2 = clock(); 
     ... 
    } 
関連する問題