使用 helgrind 提升 asio http async_client示例警告:误报

Boost asio http async_client example warning with helgrind: False positive?

本文关键字:警告 误报 client 提升 helgrind asio http async 使用      更新时间:2023-10-16

在helgrind中运行官方boos asio示例代码的http async_client示例时,会出现警告。文件中的这段代码似乎是boost/asio/detail/posix_event.hpp警告的原因:

// Signal the event and unlock the mutex.
template <typename Lock>
void signal_and_unlock(Lock& lock)
{
    BOOST_ASSERT(lock.locked());
    signalled_ = true;
    lock.unlock();
    ::pthread_cond_signal(&cond_); // Ignore EINVAL.
}

以下是valgrind/helgrind的完整输出:

jcm@Ubuntu:~/samples/async-client/build$ valgrind --tool=helgrind ./async-client stackoverflow.com error.html
==2894== Helgrind, a thread error detector
==2894== Copyright (C) 2007-2011, and GNU GPL'd, by OpenWorks LLP et al.
==2894== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==2894== Command: ./async-client stackoverflow.com error.html
==2894== 
==2894== ---Thread-Announcement------------------------------------------
==2894== 
==2894== Thread #1 is the program's root thread
==2894== 
==2894== ----------------------------------------------------------------
==2894== 
==2894== Thread #1: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
==2894==    at 0x4C2C978: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==2894==    by 0x4C2E5EA: pthread_cond_signal@* (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==2894==    by 0x43FCB2: void boost::asio::detail::posix_event::signal_and_unlock<boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex> >(boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex>&) (in /home/jcm/samples/async-client/build/async-client)
==2894==    by 0x43B659: boost::asio::detail::task_io_service::wake_one_idle_thread_and_unlock(boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex>&) (in /home/jcm/samples/async-client/build/async-client)
==2894==    by 0x43B68A: boost::asio::detail::task_io_service::wake_one_thread_and_unlock(boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex>&) (in /home/jcm/samples/async-client/build/async-client)
==2894==    by 0x43B0B8: boost::asio::detail::task_io_service::post_immediate_completion(boost::asio::detail::task_io_service_operation*) (in /home/jcm/samples/async-client/build/async-client)
==2894==    by 0x43DBFD: boost::asio::detail::resolver_service_base::start_resolve_op(boost::asio::detail::task_io_service_operation*) (in /home/jcm/samples/async-client/build/async-client)
==2894==    by 0x442F86: void boost::asio::detail::resolver_service<boost::asio::ip::tcp>::async_resolve<boost::_bi::bind_t<void, boost::_mfi::mf2<void, client, boost::system::error_code const&, boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp> >, boost::_bi::list3<boost::_bi::value<client*>, boost::arg<1> (*)(), boost::arg<2> (*)()> > >(std::shared_ptr<void>&, boost::asio::ip::basic_resolver_query<boost::asio::ip::tcp> const&, boost::_bi::bind_t<void, boost::_mfi::mf2<void, client, boost::system::error_code const&, boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp> >, boost::_bi::list3<boost::_bi::value<client*>, boost::arg<1> (*)(), boost::arg<2> (*)()> >) (in /home/jcm/samples/async-client/build/async-client)
==2894==    by 0x44187E: void boost::asio::ip::resolver_service<boost::asio::ip::tcp>::async_resolve<boost::_bi::bind_t<void, boost::_mfi::mf2<void, client, boost::system::error_code const&, boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp> >, boost::_bi::list3<boost::_bi::value<client*>, boost::arg<1> (*)(), boost::arg<2> (*)()> > >(std::shared_ptr<void>&, boost::asio::ip::basic_resolver_query<boost::asio::ip::tcp> const&, boost::_bi::bind_t<void, boost::_mfi::mf2<void, client, boost::system::error_code const&, boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp> >, boost::_bi::list3<boost::_bi::value<client*>, boost::arg<1> (*)(), boost::arg<2> (*)()> >&&) (in /home/jcm/samples/async-client/build/async-client)
==2894==    by 0x44097E: void boost::asio::ip::basic_resolver<boost::asio::ip::tcp, boost::asio::ip::resolver_service<boost::asio::ip::tcp> >::async_resolve<boost::_bi::bind_t<void, boost::_mfi::mf2<void, client, boost::system::error_code const&, boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp> >, boost::_bi::list3<boost::_bi::value<client*>, boost::arg<1> (*)(), boost::arg<2> (*)()> > >(boost::asio::ip::basic_resolver_query<boost::asio::ip::tcp> const&, boost::_bi::bind_t<void, boost::_mfi::mf2<void, client, boost::system::error_code const&, boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp> >, boost::_bi::list3<boost::_bi::value<client*>, boost::arg<1> (*)(), boost::arg<2> (*)()> >&&) (in /home/jcm/samples/async-client/build/async-client)
==2894==    by 0x43E05F: client::client(boost::asio::io_service&, std::string const&, std::string const&) (in /home/jcm/samples/async-client/build/async-client)
==2894==    by 0x437018: main (in /home/jcm/samples/async-client/build/async-client)
==2894== 
Response returned with status code 400
==2894== 
==2894== For counts of detected and suppressed errors, rerun with: -v
==2894== Use --history-level=approx or =none to gain increased speed, at
==2894== the cost of reduced accuracy of conflicting-access information
==2894== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 89 from 29)

在我看来,在发出条件变量信号之前解锁互斥锁似乎是错误的。如果是误报,请让我知道为什么上面的代码是正确的。

假设lock是与pthread_cond_(timed)wait匹配调用中使用的同一pthread_mutex_t对象的包装器对象,大多数pthreads的实现将允许您以任一顺序发出信号和解锁,因为pthread_cond_(timed)wait被定义为取消阻止条件变量并将互斥锁作为原子操作获取 - 也就是说, 在 CV 都发出信号并且调用线程都获取了互斥锁之前,它不会成功返回。

互联网谣言表明,无论操作的顺序如何,没有人会失败,但是一些线程调度器是为了在信号之后解锁发生时实现最大效率而编写的 - 而另一些线程调度器则是为了在信号之前解锁发生时实现最大效率而编写的,这意味着无论你如何编写它,你都不可能一直赢。 就个人而言,如果我维护有问题的代码,我会切换顺序,理由是它让 helgrind 满意。 您不想为了找到真正的竞争条件而涉足垃圾投诉。

我正在添加" pthread_cond_signal应该同时接受简历和互斥锁,就像pthread_cond_wait一样"添加到我的 POSIX API 拙劣列表中,以便在我获得时间机器时修复。