Helgrind 报告简单 boost::asio::thread_pool 程序中的同步错误

Helgrind reports synchronization errors in simple boost::asio::thread_pool program

我正在试验 boost::asio::thread_pool 并且 helgrind 在一个具有空任务函数的简单程序中报告错误。问题出在哪里,我该如何解决?


#include <boost/thread/mutex.hpp>
#include <boost/thread.hpp>
#include <boost/asio/thread_pool.hpp>
#include <boost/asio/post.hpp>


int main() {
    ushort thread_num = 4;
    boost::asio::thread_pool pool(thread_num);

    auto task = []() {};

    for (ushort i = 0; i < thread_num; ++i)
        boost::asio::post(pool, task);

    pool.join();

    return 0;
}

这是 helgrind 的输出:

==266706== Thread #1 is the program's root thread
==266706== 
==266706== ----------------------------------------------------------------
==266706== 
==266706== Thread #1: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
==266706==    at 0x48405D6: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_helgrind-amd64-linux.so)
==266706==    by 0x11508D: bool boost::asio::detail::posix_event::maybe_unlock_and_signal_one<boost::asio::detail::conditionally_enabled_mutex::scoped_lock>(boost::asio::detail::conditionally_enabled_mutex::scoped_lock&) (in /home/arno/Programming/test/a.out)
==266706==    by 0x111AAD: boost::asio::detail::conditionally_enabled_event::maybe_unlock_and_signal_one(boost::asio::detail::conditionally_enabled_mutex::scoped_lock&) (in /home/arno/Programming/test/a.out)
==266706==    by 0x11361E: boost::asio::detail::scheduler::wake_one_thread_and_unlock(boost::asio::detail::conditionally_enabled_mutex::scoped_lock&) (in /home/arno/Programming/test/a.out)
==266706==    by 0x1132C4: boost::asio::detail::scheduler::post_immediate_completion(boost::asio::detail::scheduler_operation*, bool) (in /home/arno/Programming/test/a.out)
==266706==    by 0x10DD99: void boost::asio::thread_pool::executor_type::post<boost::asio::detail::work_dispatcher<main::{lambda()#1}>, std::allocator<void> >(boost::asio::detail::work_dispatcher<main::{lambda()#1}>&&, std::allocator<void> const&) const (in /home/arno/Programming/test/a.out)
==266706==    by 0x10DBFB: void boost::asio::detail::initiate_post::operator()<main::{lambda()#1}&, boost::asio::thread_pool::executor_type const&>(main::{lambda()#1}&, boost::asio::thread_pool::executor_type const&) const (in /home/arno/Programming/test/a.out)
==266706==    by 0x10DB82: void boost::asio::async_result<main::{lambda()#1}, void ()>::initiate<boost::asio::detail::initiate_post, {lambda()#1}&, boost::asio::thread_pool::executor_type const&>(boost::asio::detail::initiate_post&&, {lambda()#1}&, boost::asio::thread_pool::executor_type const&) (in /home/arno/Programming/test/a.out)
==266706==    by 0x10DB54: std::enable_if<void ()::async_result_has_initiate_memfn<main::{lambda()#1}&, void ()>::value, boost::asio::async_result<std::decay<void ()::async_result_has_initiate_memfn>::type, main::{lambda()#1}&>::return_type>::type boost::asio::async_initiate<main::{lambda()#1}&, void (), boost::asio::detail::initiate_post, boost::asio::thread_pool::executor_type const&>(boost::asio::detail::initiate_post&&, void (&)()::async_result_has_initiate_memfn, boost::asio::thread_pool::executor_type const&) (in /home/arno/Programming/test/a.out)
==266706==    by 0x10DB12: boost::asio::async_result<std::decay<main::{lambda()#1}&>::type, void ()>::return_type boost::asio::post<boost::asio::thread_pool::executor_type, main::{lambda()#1}&>(boost::asio::thread_pool::executor_type const&, std::decay&&, std::enable_if<boost::asio::is_executor<boost::asio::async_result<std::decay<main::{lambda()#1}&>::type, void ()>::return_type>::value, void>::type*) (in /home/arno/Programming/test/a.out)
==266706==    by 0x10DABD: boost::asio::async_result<std::decay<main::{lambda()#1}&>::type, void ()>::return_type boost::asio::post<boost::asio::thread_pool, main::{lambda()#1}&>(boost::asio::thread_pool&, std::decay&&, std::enable_if<std::is_convertible<boost::asio::thread_pool, boost::asio::execution_context&>::value, void>::type*) (in /home/arno/Programming/test/a.out)
==266706==    by 0x10DA11: main (in /home/arno/Programming/test/a.out)

https://linux.die.net/man/3/pthread_cond_signal

The pthread_cond_broadcast() or pthread_cond_signal() functions may be called by a thread whether or not it currently owns the mutex that threads calling pthread_cond_wait() or pthread_cond_timedwait() have associated with the condition variable during their waits; however, if predictable scheduling behavior is required, then that mutex shall be locked by the thread calling pthread_cond_broadcast() or pthread_cond_signal().

这只是一个诊断警告,指示围绕条件变量进行低效调度的常见原因。如果您(作为生产者)在发出信号时没有保持互斥锁锁定,您会得到虚假的唤醒。例如。解锁互斥锁后,您对 CV 变量的更新可能已被处理,因此您的信号会导致另一个不必要的唤醒,而状态没有任何改变。

在 CV 变量的整个更新过程中保持互斥锁锁定以及相反的信号处理是有效处理的,因为消费者已经在互斥锁和 CV 上成对注册,并且向 CV 发出信号直接将消费者置于互斥量的等待列表,甚至一次都不激活线程。

虽然这只是效率低下,但不是逻辑错误。 Helgrind 只将其报告为“可疑”,而不是错误。