C++ BOOST如何在一个线程中发送信号,并在另一个线程中执行相应的插槽?

C++ BOOST如何在一个线程中发送信号,并在另一个线程中执行相应的插槽?,c++,boost,signals,C++,Boost,Signals,例如,在Qt中,如果您在GUI线程之外的线程中发出信号,那么该信号将排队并稍后在GUI线程中执行,有没有办法通过boost实现这一点 不要直接感谢,因为boost不提供事件循环 要在另一个线程中处理信号,另一个线程需要检查它应该运行并执行的处理程序队列(这通常意味着某种事件循环)。Boost没有提供,所以您需要从其他地方获取或编写它 如果您有一个不提供信号的事件循环(或使用队列实现一些简单的解决方案),那么您应该能够(ab)使用boost.signals2(不是boost.signals,因为该

例如,在Qt中,如果您在GUI线程之外的线程中发出信号,那么该信号将排队并稍后在GUI线程中执行,有没有办法通过boost实现这一点


不要直接感谢,因为boost不提供事件循环

要在另一个线程中处理信号,另一个线程需要检查它应该运行并执行的处理程序队列(这通常意味着某种事件循环)。Boost没有提供,所以您需要从其他地方获取或编写它


如果您有一个不提供信号的事件循环(或使用队列实现一些简单的解决方案),那么您应该能够(ab)使用boost.signals2(不是boost.signals,因为该版本不是线程安全的),方法是重写
操作符+=
将每个处理程序包装在某个内容中,该内容将在另一个线程中对其进行队列执行。您甚至可以为具有返回值的信号实现它(Qt不支持,但boost支持),但您必须小心避免死锁。

对于事件循环,请使用boost::asio::io\u服务。您可以在此对象内发布任务,并让另一个线程以线程安全的方式执行这些任务:

struct MyClass
{
    boost::io_service service;
    void doSomethingOp() const { ... }

    void doSomething()
    {
        service.post(boost::bind(&MyClass::doSomethingOp, this));
    }

    void loop()
    {
            service.run(); // processes the tasks
    }
};

boost::signal<void()> mySignal;

MyClass myClass;
mySignal.connect(boost::bind(&MyClass::doSomething, boost::ref(myClass)));

// launches a thread and executes myClass.loop() there
boost::thread t(boost::bind(&MyClass::loop(), boost::ref(myClass)));

// calls myClass.doSomething() in this thread, but loop() executes it in the other
mySignal(); 
struct MyClass
{
boost::io_服务;
void doSomethingOp()常量{…}
无效剂量测定法()
{
post(boost::bind(&MyClass::doSomethingOp,this));
}
void循环()
{
service.run();//处理任务
}
};
boost::信号mySignal;
MyClass MyClass;
connect(boost::bind(&MyClass::doSomething,boost::ref(MyClass));
//启动一个线程并在那里执行myClass.loop()
boost::线程t(boost::bind(&MyClass::loop(),boost::ref(MyClass));
//在此线程中调用myClass.doSomething(),但loop()在另一个线程中执行它
mySignal();

奇拉的答案是正确的,但它遗漏了一件重要的事情:
boost::thread
对象将只调用其传递的函数一次。由于在发出信号之前,
boost::io_服务
没有任何工作要做,因此线程将立即完成。为了解决这个问题,有一个
boost::asio::io_service::work
类。 在调用
io\u服务的
run()
方法之前,您应该创建一个工作对象,并将
io\u服务传递给它:

//as a class variable
std::shared_ptr<boost::asio::io_service::work> worker;

//before you call run() of the io_service yourIOService
worker = std::make_shared<boost::asio::io_service::work>(yourIOService);

//If you want the service to stop
worker.reset();
//作为类变量
std::共享ptr工作人员;
//在调用io_服务的run()之前,请先调用yourIOService
worker=std::使_共享(yourIOService);
//如果你想让服务停止
worker.reset();

注意:在撰写本文时(boost 1.67),此方法已被弃用,您应该使用
io\U上下文::执行器\U工作\U保护
(基本上与
io\U服务::工作相同的功能)。但是,使用新方法时我无法编译,工作解决方案仍在boost 1.67中工作。

由于某种原因,boost::asio::executor\u work\u guard的赋值运算符被删除,但您仍然可以构造它

下面是我的代码版本,它发布了一些可移动的
事件
对象,并在运行
io\u context::run()的线程上对其进行处理:

class-MyClass{
公众:
MyClass():mu-work(boost::asio::make-work\u-guard(mu-service)){}
大小\u t循环(){
返回m_service.run();
}
无效停止(){
m_work.reset();
}
无效剂量测定(事件和e){
m_service.post([this,e=std::move(e)]{doSomethingOp(std::move(e));});
}
私人:
无效doSomethingOp(常数事件和事件){
...
}
//数据:
boost::asio::io_上下文m_服务;
推进::asio::执行者工作,守卫工作;
};

它需要C++14,并使用VS2017和GCC 6.4以及线程和内存清洗剂进行了测试。

以下是上述
io\u服务
executor\u work\u guard
signals2::signal
的完整示例

  • io_服务
    是事件循环处理程序
  • executor\u work\u guard
    确保m\u service.run()不会只执行一次
  • 信号
    /
    插槽
    将发送器和接收器解耦
  • 线程
    运行
    io\u服务的所有进程
#包括
#包括
#包括
#包括
类IOService
{
公众:
IOService():m_worker(boost::asio::make_work\u guard(m_service)){}
~IOService(){}
//接收信号的插槽
void slotMessage(std::string msg)
{
m_service.post(boost::bind(&IOService::process,this,msg));
}
//启动/关闭后台线程
boolstart()
{
如果(m_已启动)
返回true;
m_start=true;
//启动读卡器线程
m_thread=boost::thread(boost::bind(&IOService::loop,this));
返回m_已启动;
}
void循环()
{
m_service.run();
}
无效关闭()
{
m_worker.reset();
if(m_thread.joinable())
m_thread.join();
m_start=false;
}
//过程
无效进程(std::string msg)
{
printf(“进程%s\n”,msg.c_str());
}
私人:
bool m_start=false;
boost::asio::io_服务m_服务;
执行者、工作者、守卫者、工人;
boost::线程m_线程;
};
int main()
{
//服务实例
IOService服务;
serv.start();
//信号到插槽
boost::signals2::signalsmessage;
connect(boost::bind(&IOService::slotMessage,boost::ref(serv),_1));
//发一个信号
信号信息(“abc”);
//等待并退出
boost::this_thread::sleep(boost::chrono::seconds(2));
serv.close();
}

THX用于此非常有用的示例!由于boost::signal已被弃用,我不得不使用boost::signals2::signal。
class MyClass {
public:
  MyClass () : m_work(boost::asio::make_work_guard(m_service)) {}

  size_t loop() {
    return m_service.run();
  }

  void stop() {
    m_work.reset();
  }

  void doSomething(Event&& e) {
    m_service.post([this, e=std::move(e)]{ doSomethingOp(std::move(e)); });
  }

private:
  void doSomethingOp(const Event& event) {
    ...
  }
//data:
  boost::asio::io_context m_service;
  boost::asio::executor_work_guard<boost::asio::io_context::executor_type> m_work;
};
#include <boost/thread.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/signals2/signal.hpp>

class IOService
{
public:
  IOService() : m_worker(boost::asio::make_work_guard(m_service)) {}
  ~IOService() {}

  // slot to receive signal
  void slotMessage(std::string msg)
  {
    m_service.post(boost::bind(&IOService::process, this, msg));
  }

  // start/close background thread
  bool start()
  {
    if (m_started)
      return true;
    m_started = true;

    // start reader thread
    m_thread = boost::thread(boost::bind(&IOService::loop, this));
    return m_started;
  }

  void loop()
  {
    m_service.run();
  }

  void close()
  {
    m_worker.reset();
    if (m_thread.joinable())
      m_thread.join();
    m_started = false;
  }

  // process
  void process(std::string msg)
  {
    printf("process %s\n", msg.c_str());
  }

private:
  bool m_started = false;
  boost::asio::io_service m_service;
  boost::asio::executor_work_guard<boost::asio::io_context::executor_type> m_worker;
  boost::thread m_thread;
};

int main()
{
  // service instance
  IOService serv;
  serv.start();

  // signal to slot
  boost::signals2::signal<void(std::string)> signalMessage;
  signalMessage.connect(boost::bind(&IOService::slotMessage, boost::ref(serv), _1));

  // send one signal
  signalMessage("abc");

  // wait and quit
  boost::this_thread::sleep(boost::chrono::seconds(2));
  serv.close();
}