gpt4 book ai didi

c++ - 提升条件变量问题

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:26:34 27 4
gpt4 key购买 nike

以下较大程序的最小代码示例将命令从客户端线程发送到 asio io_service 对象。 io_service 对象(在 Ios 类中)正在一个线程中运行。发送命令后,客户端线程会一直等待,直到 Ios 对象(通过 Cmd::NotifyFinish())通知它已完成。

此示例似乎在 Linux Ubuntu 11.04 上运行,boost 1.46 正常,但在 Windows 7 boost 1.46 上它断言。

我怀疑这与 Cmd::NotifyFinish() 中的锁定有关。当我将锁移出嵌套范围以便在锁的范围内调用 waitConditionVariable_.notify_one() 时它不会在 Windows 7 上崩溃。但是,boost::thread 文档指出 notify_one() 不需要在锁内调用。

堆栈跟踪(下方)显示它在调用 notify_one() 时断言。好像在调用 notify 之前 cmd 对象已经消失了...

如何使这个线程安全而不断言?

#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/bind.hpp>
#include <iostream>

class Cmd
{
public:
Cmd() : cnt_(0), waitPred_(false), waiting_(false)
{
}
virtual ~Cmd()
{
}
void BindInfo(int CmdSeq)
{
cnt_ = CmdSeq;
}
void NotifyFinish()
{
// call by service thread...
{
boost::mutex::scoped_lock lock(waitMutex_);
waitPred_ = true;
if (!waiting_)
{
// don't need to notify as isn't waiting
return;
}
}
waitConditionVariable_.notify_one();
}
void Wait()
{
// called by worker threads
boost::mutex::scoped_lock lock(waitMutex_);
waiting_ = true;
while (!waitPred_)
waitConditionVariable_.wait(lock);
}
int cnt_;
private:

boost::mutex waitMutex_;
boost::condition_variable waitConditionVariable_;
bool waitPred_;
bool waiting_;
};


class Ios
{
public:
Ios() : timer_(ios_), cnt_(0), thread_(boost::bind(&Ios::Start, this))
{
}
void Start()
{
timer_.expires_from_now(boost::posix_time::seconds(5));
timer_.async_wait(boost::bind(&Ios::TimerHandler, this, _1));
ios_.run();
}
void RunCmd(Cmd& C)
{
ios_.post(boost::bind(&Ios::RunCmdAsyn, this, boost::ref(C)));
}

private:
void RunCmdAsyn(Cmd& C)
{
C.BindInfo(cnt_++);
C.NotifyFinish();
}
void TimerHandler(const boost::system::error_code& Ec)
{
if (!Ec)
{
std::cout << cnt_ << "\n";
timer_.expires_from_now(boost::posix_time::seconds(5));
timer_.async_wait(boost::bind(&Ios::TimerHandler, this, _1));
}
else
exit(0);
}

boost::asio::io_service ios_;
boost::asio::deadline_timer timer_;
int cnt_;
boost::thread thread_;
};

static Ios ios;

void ThreadFn()
{
while (1)
{
Cmd c;
ios.RunCmd(c);
c.Wait();
//std::cout << c.cnt_ << "\n";
}
}

int main()
{
std::cout << "Starting\n";
boost::thread_group threads;
const int num = 5;

for (int i = 0; i < num; i++)
{
// Worker threads
threads.create_thread(ThreadFn);
}
threads.join_all();

}

堆栈跟踪

msvcp100d.dll!std::_Debug_message(const wchar_t * message, const wchar_t * file, unsigned int line)  Line 15    C++
iosthread.exe!std::_Vector_const_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > >::_Compat(const std::_Vector_const_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > > & _Right) Line 238 + 0x17 bytes C++
iosthread.exe!std::_Vector_const_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > >::operator==(const std::_Vector_const_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > > & _Right) Line 203 C++
iosthread.exe!std::_Vector_const_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > >::operator!=(const std::_Vector_const_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > > & _Right) Line 208 + 0xc bytes C++
iosthread.exe!std::_Debug_range2<std::_Vector_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > > >(std::_Vector_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > > _First, std::_Vector_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > > _Last, const wchar_t * _File, unsigned int _Line, std::random_access_iterator_tag __formal) Line 715 + 0xc bytes C++
iosthread.exe!std::_Debug_range<std::_Vector_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > > >(std::_Vector_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > > _First, std::_Vector_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > > _Last, const wchar_t * _File, unsigned int _Line) Line 728 + 0x6c bytes C++
iosthread.exe!std::find_if<std::_Vector_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > >,bool (__cdecl*)(boost::intrusive_ptr<boost::detail::basic_cv_list_entry> const &)>(std::_Vector_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > > _First, std::_Vector_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > > _Last, bool (const boost::intrusive_ptr<boost::detail::basic_cv_list_entry> &)* _Pred) Line 92 + 0x54 bytes C++
iosthread.exe!std::remove_if<std::_Vector_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > >,bool (__cdecl*)(boost::intrusive_ptr<boost::detail::basic_cv_list_entry> const &)>(std::_Vector_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > > _First, std::_Vector_iterator<std::_Vector_val<boost::intrusive_ptr<boost::detail::basic_cv_list_entry>,std::allocator<boost::intrusive_ptr<boost::detail::basic_cv_list_entry> > > > _Last, bool (const boost::intrusive_ptr<boost::detail::basic_cv_list_entry> &)* _Pred) Line 1848 + 0x58 bytes C++
iosthread.exe!boost::detail::basic_condition_variable::notify_one() Line 267 + 0xb4 bytes C++
iosthread.exe!Cmd::NotifyFinish() Line 41 C++

最佳答案

问题是条件变量是 Cmd 的成员由客户端线程创建并在等待完成时由该客户端线程销毁的对象。

所以你有一个竞争条件:

  • boost::condition_variable::notify_one()在“服务线程”上调用
  • 取消阻塞正在等待该条件变量的客户端线程
  • 然后,客户端线程可以销毁服务线程在调用 notify_one 时仍在使用的条件变量。 .

所以您观察到“好像 cmd 对象在调用 notify 之前消失了”,我认为这几乎就是发生的事情。除了 Cmd对象在 notify_one() 之前没有消失被调用时,它消失了 notify_one()正在做它的工作。您的另一条注意事项是“boost::thread 文档指出notify_one() 不需要在锁内调用”是正确的,但这并不意味着可以在notify_one() 之前销毁条件变量。已经回来了。

您需要管理 Cmd 的生命周期对象,以便服务线程在它被销毁之前使用它完成 - 持有 Cmd 中的互斥锁对象同时 notify_one()被调用是一种方法(如您所见)。或者您可以从 Cmd 中提取条件变量对象,使其生命周期独立于 Cmd对象(也许 shared_ptr<> 可以帮助解决这个问题)。

另请注意,我相信 waiting_ Cmd的成员类是多余的 - 你可以调用notify_one()notify_all()当条件变量上没有服务员时 - 它已经在为您进行检查(我认为这不会造成任何伤害,只是它的复杂性不需要在 Cmd 类中)。

关于c++ - 提升条件变量问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6644631/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com