2011-07-28 11 views
7

私はプロジェクトの一環として、ロガー関数を作成しています。このロガー機能は、プログラムが何かを記録したいときに電子メールを送信します。 SMTPサーバーが応答しなかったので、別のスレッドでメールを送信することに決めました。 このスレッドは、ログ機能によって満たされたstd :: dequeからメッセージを読み取ります。 次のようにスレッドが設定され、次のように複数のスレッドとmutexを使用する場合のmutexでのアサーション

while (!boost::this_thread::interruption_requested()) 
{ 
    EmailItem emailItem; 
    { 
    boost::unique_lock<boost::mutex> lock(mMutex); 
    while (mEmailBuffer.empty()) 
     mCond.wait(lock); 

    bufferOverflow = mBufferOverflow; 
    mBufferOverflow = false; 
    nrOfItems = mEmailBuffer.size(); 

    if (nrOfItems > 0) 
    { 
     emailItem = mEmailBuffer.front(); 
     mEmailBuffer.pop_front(); 
    } 
    } 

    if (nrOfItems > 0) 
    { 
     bool sent = false; 
     while(!sent) 
     { 
      try 
      { 
      ..... Do something with the message ..... 
      { 
       boost::this_thread::disable_interruption di; 
       boost::lock_guard<boost::mutex> lock(mLoggerMutex); 
       mLogFile << emailItem.mMessage << std::endl; 
      } 
      sent = true; 
      } 
      catch (const std::exception &e) 
      { 
      // Unable to send mail, an exception occurred. Retry sending it after some time 
      sent = false; 
      boost::this_thread::sleep(boost::posix_time::seconds(LOG_WAITBEFORE_RETRY)); 
      } 
     } 
    } 
} 

関数log()は両端キュー(mEmailBuffer)に新しいメッセージが追加されます。

{ 
    boost::lock_guard<boost::mutex> lock(mMutex); 
    mEmailBuffer.push_back(e); 
    mCond.notify_one(); 
} 

すると、メインプログラムが終了、のデストラクタロガーオブジェクトが呼び出されます。それがうまくいかないところこれは、エラーでアプリケーションのクラッシュです:

/usr/include/boost/thread/pthread/mutex.hpp:45: boost::mutex::~mutex(): Assertion `!pthread_mutex_destroy(&m)' failed. 

デストラクタは、単にスレッドに割り込みを呼び出し、それに参加する:メインプログラムで

mQueueThread.interrupt(); 
mQueueThread.join(); 

、私は複数の使用しますブーストスレッディングとミューテックスを使用する別のクラスでも、これがこの動作を引き起こす可能性がありますか?ロガーオブジェクトのデストラクタを呼び出さないと、エラーは発生しません。また、ロガーオブジェクトを使用して何も実行しません。

私は何か非常に間違っていると思うし、いくつかのクラスに分割された複数のスレッドを使用するとスレッドライブラリにバグがあります。 誰かがこのエラーの理由を考えているのですか?

EDIT: @Andy Tは、できるだけコードを提案して削除しました。私は別のスレッドで実行されている関数のほとんどすべてを削除しました。スレッドは次のようになります。

void Vi::Logger::ThreadedQueue() 
{ 
    bool bufferOverflow = false; 
    time_t last_overflow = 0; 
    unsigned int nrOfItems = 0; 

    while (!boost::this_thread::interruption_requested()) 
    { 
    EmailItem emailItem; 
    // Check for new log entries 
    { 
     boost::unique_lock<boost::mutex> lock(mMutex); 
     while (mEmailBuffer.empty()) 
     mCond.wait(lock); 
    } 
    } 
} 

問題は解決しません。 mMutexは(unique_lockのを使用しての組み合わせでロック解除)して、スレッドを中断されていないということができるかもしれない

#0 0x00007ffff53e9ba5 in raise (sig=<value optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 
#1 0x00007ffff53ed6b0 in abort() at abort.c:92 
#2 0x00007ffff53e2a71 in __assert_fail (assertion=0x7ffff7bb6407 "!pthread_mutex_lock(&m)", file=<value optimized out>, line=50, function=0x7ffff7bb7130 "void boost::mutex::lock()") at assert.c:81 
#3 0x00007ffff7b930f3 in boost::mutex::lock (this=0x7fffe2c1b0b8) at /usr/include/boost/thread/pthread/mutex.hpp:50 
#4 0x00007ffff7b9596c in boost::unique_lock<boost::mutex>::lock (this=0x7fffe48b3b40) at /usr/include/boost/thread/locks.hpp:349 
#5 0x00007ffff7b958db in boost::unique_lock<boost::mutex>::unique_lock (this=0x7fffe48b3b40, m_=...) at /usr/include/boost/thread/locks.hpp:227 
#6 0x00007ffff6ac2bb7 in Vi::Logger::ThreadedQueue (this=0x7fffe2c1ade0) at /data/repos_ViNotion/stdcomp/Logging/trunk/src/Logger.cpp:198 
#7 0x00007ffff6acf2b2 in boost::_mfi::mf0<void, Vi::Logger>::operator() (this=0x7fffe2c1d890, p=0x7fffe2c1ade0) at /usr/include/boost/bind/mem_fn_template.hpp:49 
#8 0x00007ffff6acf222 in boost::_bi::list1<boost::_bi::value<Vi::Logger*> >::operator()<boost::_mfi::mf0<void, Vi::Logger>, boost::_bi::list0> (this=0x7fffe2c1d8a0, f=..., a=...) at /usr/include/boost/bind/bind.hpp:253 
#9 0x00007ffff6acf1bd in boost::_bi::bind_t<void, boost::_mfi::mf0<void, Vi::Logger>, boost::_bi::list1<boost::_bi::value<Vi::Logger*> > >::operator() (this=0x7fffe2c1d890) at /usr/include/boost/bind/bind_template.hpp:20 
#10 0x00007ffff6aceff2 in boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, Vi::Logger>, boost::_bi::list1<boost::_bi::value<Vi::Logger*> > > >::run (this=0x7fffe2c1d760) 
    at /usr/include/boost/thread/detail/thread.hpp:56 
#11 0x00007ffff2cc5230 in thread_proxy() from /usr/lib/libboost_thread.so.1.42.0 
#12 0x00007ffff4d87971 in start_thread (arg=<value optimized out>) at pthread_create.c:304 
#13 0x00007ffff549c92d in clone() at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112 
#14 0x0000000000000000 in ??() 

:問題のバックトラックは、しかし、私の最初のコードとは異なる何かを示しましたか?

答えて

3

終了する前にスレッドに参加しますか? tyzが示唆しているように、あなたのスレッドは、mutexが破壊されたときでもロックを保持し続けることができます。

[EDIT]

あなたはそれがW/Oそれを助けるのは難しい、コンパイルすることができる完全な例を提供し、実行されませんでした。

チェックあなたの1のようになります。この単純な例:

#include <boost/thread.hpp> 
#include <boost/bind.hpp> 
#include <queue> 

class Test 
{ 
public: 
    Test() 
    { 
     thread = boost::thread(boost::bind(&Test::thread_func, this)); 
    } 

    ~Test() 
    { 
     thread.interrupt(); 
     thread.join(); 
    } 

    void run() 
    { 
     for (size_t i = 0; i != 10000; ++i) { 
      boost::lock_guard<boost::mutex> lock(mutex); 
      queue.push(i); 
      condition_var.notify_one(); 
     } 
    } 

private: 
    void thread_func() 
    { 
     while (!boost::this_thread::interruption_requested()) 
     { 
      { 
       boost::unique_lock<boost::mutex> lock(mutex); 
       while (queue.empty()) 
        condition_var.wait(lock); 
       queue.pop(); 
      } 
     } 
    } 

private: 
    boost::thread thread; 
    boost::mutex mutex; 
    boost::condition_variable condition_var; 
    std::queue<int> queue; 
}; 

int main() 
{ 
    Test test; 
    test.run(); 

    return 0; 
} 

は、あなたのケースにご返信用

+0

はい、終了する前にスレッドに参加します。また、私が知っている限り、ミューテックスがスレッドにロックされている場所には中断ポイントはありません。したがって、スレッドが中断されたときにスレッドがまだロックされていないことを期待しません。 – Tim

+0

再度参加する前にあなたのミューテックス(正しいもの)が削除されていないことを再度確認してください。 –

+0

両方のミューテックスは、Loggerクラスのメンバー変数です。このクラスのデストラクタはスレッド上で 'interrupt()'と 'join()'関数を呼び出します。したがって、ミューテックスはスレッドが結合されてもまだ生きているはずです。 – Tim

1

削除する前にmutexのロックを解除する必要があります。

+0

感謝を比較します。私のコードでは、スコープロックを使ってmutexをロックしています。したがって、スコープが閉じられると自動的にロックが解除されるはずです。 – Tim

+0

@Tim、私は懸命に努力しましたが、与えられたコードの中に何らかのエラーが見つかりませんでした。それでもエラーは通常、ロックされたmutexの削除によって発生します。 –

+0

関数の最後に明示的にmutexのロックを解除しましたが、残念ながら成功しませんでした。 mMutex.unlock(); mLoggerMutex.unlock(); – Tim

関連する問題