一個線程餓死的例子


陳碩的《Linux多線程服務端編程:使用muduo C++網絡庫》中2.2一節中寫了一個簡單的容量無限的BlockingQueue,其中出隊函數enqueue()中,每次添加元素都會調用pthread_cond_signal(封裝成了Condition::notify()).然后提了一個問題,如果改成只在queue.size()從0變成1的時候才調用Conditon::notify()會如何.

根據C++11寫了個,BlockingQueue的實現放在了這里,test的實現放在了這里

test具體就是1個生產者4個消費者

gdb跟進用thread apply all bt得出了4個消費者狀態

(gdb) thread apply all bt

Thread 5 (Thread 0x7ffff57cf700 (LWP 4223)):
#0 0x00007ffff7bc8404 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/x86_64-linux-gnu/libpthread.so.0
#1 0x00007ffff79664dc in std::condition_variable::wait(std::unique_lock<std::mutex>&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#2 0x000000000040b461 in std::condition_variable::wait<BlockQueue::BlockQueue<int>::dequeue()::{lambda()#1}>(std::unique_lock<std::mutex>&, BlockQueue::BlockQueue<int>::dequeue()::{lambda()#1}) (this=0x612230 <queue+40>, __lock=..., __p=...) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/condition_variable:93
#3 0x0000000000409a0a in BlockQueue::BlockQueue<int>::dequeue (this=0x612208 <queue>) at /home/hr/code/somecode/test/../BlockQueue/BlockQueue.h:46
#4 0x0000000000409487 in test_pop () at /home/hr/code/somecode/test/testStarvation.cc:24
#5 0x000000000040c66f in std::_Bind_simple<int (*())()>::_M_invoke<>(std::_Index_tuple<>) (this=0x6136f0) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1731
#6 0x000000000040c645 in std::_Bind_simple<int (*())()>::operator()() (this=0x6136f0) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1720
#7 0x000000000040c3f9 in std::thread::_Impl<std::_Bind_simple<int (*())()> >::_M_run() (this=0x6136d8) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/thread:115
#8 0x00007ffff7969a60 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#9 0x00007ffff7bc4184 in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
#10 0x00007ffff70d0ffd in clone () from /lib/x86_64-linux-gnu/libc.so.6

Thread 4 (Thread 0x7ffff5fd0700 (LWP 4222)):
#0 0x00007ffff7bc8404 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/x86_64-linux-gnu/libpthread.so.0
#1 0x00007ffff79664dc in std::condition_variable::wait(std::unique_lock<std::mutex>&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#2 0x000000000040b461 in std::condition_variable::wait<BlockQueue::BlockQueue<int>::dequeue()::{lambda()#1}>(std::unique_lock<std::mutex>&, BlockQueue::BlockQueue<int>::dequeue()::{lambda()#1}) (this=0x612230 <queue+40>, __lock=..., __p=...) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/condition_variable:93
#3 0x0000000000409a0a in BlockQueue::BlockQueue<int>::dequeue (this=0x612208 <queue>) at /home/hr/code/somecode/test/../BlockQueue/BlockQueue.h:46
#4 0x0000000000409487 in test_pop () at /home/hr/code/somecode/test/testStarvation.cc:24
#5 0x000000000040c66f in std::_Bind_simple<int (*())()>::_M_invoke<>(std::_Index_tuple<>) (this=0x613580) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1731
#6 0x000000000040c645 in std::_Bind_simple<int (*())()>::operator()() (this=0x613580) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1720
#7 0x000000000040c3f9 in std::thread::_Impl<std::_Bind_simple<int (*())()> >::_M_run() (this=0x613568) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/thread:115
#8 0x00007ffff7969a60 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#9 0x00007ffff7bc4184 in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
#10 0x00007ffff70d0ffd in clone () from /lib/x86_64-linux-gnu/libc.so.6

Thread 3 (Thread 0x7ffff67d1700 (LWP 4221)):
#0 0x00007ffff7bc8404 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/x86_64-linux-gnu/libpthread.so.0
#1 0x00007ffff79664dc in std::condition_variable::wait(std::unique_lock<std::mutex>&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#2 0x000000000040b461 in std::condition_variable::wait<BlockQueue::BlockQueue<int>::dequeue()::{lambda()#1}>(std::unique_lock<std::mutex>&, BlockQueue::BlockQueue<int>::dequeue()::{lambda()#1}) (this=0x612230 <queue+40>, __lock=..., __p=...) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/condition_variable:93
#3 0x0000000000409a0a in BlockQueue::BlockQueue<int>::dequeue (this=0x612208 <queue>) at /home/hr/code/somecode/test/../BlockQueue/BlockQueue.h:46
#4 0x0000000000409487 in test_pop () at /home/hr/code/somecode/test/testStarvation.cc:24
#5 0x000000000040c66f in std::_Bind_simple<int (*())()>::_M_invoke<>(std::_Index_tuple<>) (this=0x613410) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1731
#6 0x000000000040c645 in std::_Bind_simple<int (*())()>::operator()() (this=0x613410) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1720
#7 0x000000000040c3f9 in std::thread::_Impl<std::_Bind_simple<int (*())()> >::_M_run() (this=0x6133f8) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/thread:115
#8 0x00007ffff7969a60 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#9 0x00007ffff7bc4184 in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
#10 0x00007ffff70d0ffd in clone () from /lib/x86_64-linux-gnu/libc.so.6

Thread 1 (Thread 0x7ffff7fd3780 (LWP 4215)):
#0 main () at /home/hr/code/somecode/test/testStarvation.cc:42
#1 0x00007ffff6ff4f45 in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6
#2 0x0000000000409359 in _start ()

而gdb的p queue.queue_.size()則得出了

[Thread 0x7ffff67d1700 (LWP 9075) exited]
$1 = 9

可見消費者生產的2個線程並未被消費,因為在第一條插入之后觸發0到1的轉變,觸發notify,但是由於接下來的pop和第二此push的順序不能確定,即:

queue_.pop_front()               與               if(queue_.size() == 1)

如果是pop晚於了push而第二次鎖lock的是push而非pop,那么只有一個消費者會被喚醒,其他的消費者就陷入了starvation而永遠陷入pthread_cond_wait()等待中


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM