2011-07-28 16 views
7

Bir projenin bir parçası olarak bir günlük kaydedici işlevi yazdım. Bu logger işlevi, program bir şeyleri kaydetmek istediğinde bir e-posta gönderir. SMTP sunucusunun yanıt vermediğinden beri, postaların ayrı bir iş parçacığına gönderilmesine karar verdim. Bu iş parçacığı, günlük kaydı işlevi tarafından doldurulan bir std :: deque'den gelen iletileri okur.Birden çok iş parçacığı ve muteks kullanırken muteks üzerinde onaylama

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

fonksiyon log() deque (mEmailBuffer) aşağıdaki gibi yeni bir mesaj ekler: şu şekildedir: iplik kurulduğundan

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

zaman ana program çıkışlar, yıkıcı logger nesnesi denir.

yıkıcı sadece iş parçacığı üzerinde bir kesme çağırır ve sonra katılır

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

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

, birden kullanmak yanlış giderse budur, uygulama bir hata ile çöker Boost ve mutex'i de kullanan farklı sınıflar bu davranışa neden olabilir mi? Logger nesnesinin yok edicisini çağırmak, logger nesnesini kullanıp başka bir şey yapmamak gibi, hiçbir hatayla sonuçlanmaz.

Tahminim çok yanlış bir şey yapıyorum ya da çeşitli sınıflara bölünmüş birden fazla iş parçacığı kullanırken iş parçacığı kitaplığında bir hata var. Bu hatanın sebebinin ne olabileceği hakkında bir fikri olan var mı?

DÜZENLEME: @Andy T önerdim ve kodu olabildiğince çıkardım. Farklı bir iş parçacığında çalıştırılan işlevdeki neredeyse her şeyi kaldırdım. Iş parçacığı şimdi görünüyor:

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

Sorun hala devam ediyor.

#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 ??() 

o mMutex bir unique_lock() kullanarak ve sonra iplik kesintiye kombinasyonunda kilidi olmadığını mümkün olabilirdi: Sorunun Geri Adım ancak bana ilk kodundan farklı bir şey gösterdi?

cevap

3

Çıkmadan önce iş parçanıza katılıyor musunuz? tyz önerildiği gibi, iş parçacığınız muteks imha edildiğinde kilitli kalabilir.

derlenmiş ve çalıştırılabilir eksiksiz bir örnek vermedi, bu w/o o yardım etmek zordur [DÜZENLE].

onay senin birine benzer olmalıdır bu basit örnek:

#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; 
} 

davanızı ile Cevabınız için

+0

Evet, çıkmadan önce iş parçacığına katıldım. Ayrıca, farkında olduğum sürece, bir muteksin iş parçasında kilitlendiği yerlerde hiçbir kesinti noktası yoktur. Bu nedenle, iş parçacığının kesintiye uğradığında kilitli bir mutex kilitlenmesini beklemem. – Tim

+0

Lütfen, muteks'inizin (doğru olan) –

+0

katılmadan önce silinmediğini bir kez daha kontrol edin. Her iki muteks de Logger sınıfının üye değişkenleridir. Bu sınıfın yıkıcısı, iş parçacığında 'interrupt()' ve 'join()' işlevlerini çağırır. Bu yüzden muteksler, eğer doğruysa, iplik birleştirildiğinde hala hayatta olmalıdır. Son çare olarak – Tim

1

Silmeden önce muteks'i açmanız gerekir.

+0

Teşekkür karşılaştırın. Kodumda, sadece muteksleri kilitlemek için kapsamlı kilitler kullanıyorum. Bu nedenle, kapsam kapalı olduğundan otomatik olarak açılmalıdır, değil mi? – Tim

+0

@Tim, Denedim ama verilen kod içinde herhangi bir hata bulamadım.Hala aldığınız hata genellikle kilitli muteks silinmesi ile sonuçlanır. –

+0

Mutekslerin fonksiyonun sonunda açık bir şekilde kilidini açmayı, maalesef başarı olmadan ekledim: mMutex.unlock(); mLoggerMutex.unlock(); – Tim

İlgili konular