一個線程餓死的例子
陳碩的《Linux多線程服務端編程:使用muduo C++網絡庫》中2.2一節中寫了一個簡單的容量無限的BlockingQueue,其中出隊函數enqueue()中,每次添加元素都會調用pthread_cond_signal(封裝成了Condition::notify()).然後提了一個問題,如果改成只在queue.size()從0變成1的時候才調用Conditon::notify()會如何.
根據C++11寫了個,BlockingQueue的實現放在了這裏,test的實現放在了這裏
test具體就是1個生產者2個消費者
多次測試發現有很小概率出現了
gdb跟進用thread apply all bt得出了兩個消費者
Thread 4 (Thread 0x7ffff5fd0700 (LWP 9076)):
#0 0x00007ffff7bcaf1c in __lll_lock_wait () from /lib/x86_64-linux-gnu/libpthread.so.0
#1 0x00007ffff7bc6649 in _L_lock_909 () from /lib/x86_64-linux-gnu/libpthread.so.0
#2 0x00007ffff7bc6470 in pthread_mutex_lock () from /lib/x86_64-linux-gnu/libpthread.so.0
#3 0x00000000004099c3 in __gthread_mutex_lock (__mutex=0x612348 <queue>) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/x86_64-linux-gnu/c++/4.8/bits/gthr-default.h:748
#4 0x000000000040ae95 in std::mutex::lock (this=0x612348 <queue>) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/mutex:134
#5 0x000000000040ae6c in std::unique_lock<std::mutex>::lock (this=0x7ffff5fcfe08) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/mutex:511
#6 0x000000000040acfb in std::unique_lock<std::mutex>::unique_lock (this=0x7ffff5fcfe08, __m=...) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/mutex:443
#7 0x0000000000409c7e in BlockQueue::BlockQueue<int>::dequeue (this=0x612348 <queue>) at /home/hr/code/somecode/test/../BlockQueue/BlockQueue.h:53
#8 0x00000000004097b7 in test_pop () at /home/hr/code/somecode/test/testStarvation.cc:26
#9 0x000000000040df7f in std::_Bind_simple<int (*())()>::_M_invoke<>(std::_Index_tuple<>) (this=0x613590) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1731
#10 0x000000000040df55 in std::_Bind_simple<int (*())()>::operator()() (this=0x613590) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1720
#11 0x000000000040ddd9 in std::thread::_Impl<std::_Bind_simple<int (*())()> >::_M_run() (this=0x613578) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/thread:115
#12 0x00007ffff7969a60 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#13 0x00007ffff7bc4184 in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
#14 0x00007ffff70d0ffd in clone () from /lib/x86_64-linux-gnu/libc.so.6
Thread 3 (Thread 0x7ffff67d1700 (LWP 9075)):
#0 0x00007ffff7bcbb9d in nanosleep () from /lib/x86_64-linux-gnu/libpthread.so.0
#1 0x000000000040b76e in std::this_thread::sleep_for<long, std::ratio<1l, 1l> > (__rtime=...) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/thread:279
#2 0x0000000000409d3a in BlockQueue::BlockQueue<int>::dequeue (this=0x612348 <queue>) at /home/hr/code/somecode/test/../BlockQueue/BlockQueue.h:63
#3 0x00000000004097b7 in test_pop () at /home/hr/code/somecode/test/testStarvation.cc:26
#4 0x000000000040df7f in std::_Bind_simple<int (*())()>::_M_invoke<>(std::_Index_tuple<>) (this=0x613420) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1731
#5 0x000000000040df55 in std::_Bind_simple<int (*())()>::operator()() (this=0x613420) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1720
#6 0x000000000040ddd9 in std::thread::_Impl<std::_Bind_simple<int (*())()> >::_M_run() (this=0x613408) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/thread:115
#7 0x00007ffff7969a60 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#8 0x00007ffff7bc4184 in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
#9 0x00007ffff70d0ffd in clone () from /lib/x86_64-linux-gnu/libc.so.6
而gdb的p queue.queue_.size()則得出了
[Thread 0x7ffff67d1700 (LWP 9075) exited]
$1 = 2
可見消費者生產的2個線程並未被消費,因為在第一條插入之後觸發0到1的轉變,觸發notify,但是由於接下來的pop和第二此push的順序不能確定,如果是pop晚於了push而第二次鎖lock的是push而非pop,那麽就產生starvation
一個線程餓死的例子