安全线程终止

时间:2013-04-11 11:46:31

标签: c++ windows multithreading visual-c++ thread-safety

工作线程处理数据库更新。当应用程序结束时,我想终止它,但不要让它让db不一致。所以我在每个重要的db操作之前使用标志。过了一会儿,代码已满了if:

      void MyWorkerThread::RunMethod(){
      if (false == m_Manager->GetShutdownFlag()) {
         DoSomethingOnDB();
      }
      if (false == m_Manager->GetShutdownFlag()) {
         DoSomethingMoreOnDB();
      }
      ...

那么,有没有其他方法来处理关机而不发送垃圾邮件如此多?

5 个答案:

答案 0 :(得分:2)

最好通过某些同步对象(事件,锁,互斥,信号量,临界区,等等......)来同步线程,以便主线程可以等待工作线程。

这里有一个竞争条件:如果在评估if条件之后和执行DB操作之前立即引发关闭标志会怎么样?

以下是互斥量作为众所周知的同步原语的说明,但有更好的方法。

主线程:

int main() {
    ... wait for signal to exit the app
    // the DB operations are running on another thread
    ...
    // assume that we start shutdown here
    // also assume that there is some global mutex g_mutex
    // following line blocks if mutex is locked in worker thread:
    std::lock_guard<std::mutex> lock(g_mutex); 
    Cleanup(); //  should also ensure that worker is stopped
}

工作线程:

void MyWorkerThread::RunMethod() 
{
  {
    std::lock_guard<std::mutex> lock(g_mutex); 
    DoSomethingOnDB();
  }
  // some other, non locked execution which doesn't prevent
  // main thread from exiting
  ...
  {
     std::lock_guard<std::mutex> lock(g_mutex);
     DoSomethingMoreOnDB();
  }
}
显然你不想重复所有的锁定,你应该把它包起来:

  void MyWorkerThread::RunMethod() 
  {
    Execute(DoSomethingOnDB);
    ...
    Execute(DoSomethingMoreOnDB);
  }

  void MyWorkerThread::Execute(DatabaseFn fn) 
  {
     std::lock_guard<std::mutex> lock(g_mutex); 
     fn();
  }

答案 1 :(得分:1)

您的应用程序中是否已有ReaderWriter Locks?您应该将数据库关闭视为写入操作,并在启动之前获取Writer Lock。然后,一旦结束正在进行,其他Read(获取Reader Lock)或Write操作(获得Writer Lock)都不会启动。

答案 2 :(得分:1)

您的代码中有一个模式,这意味着您可以将其抽象为函数:

void MyWorkerThread::execDBCommand(auto cmd){
    if  (! m_Manager->GetShutdownFlag()) {
        cmd();
    } else throw std::runtime_error("shutdown"); // or a custom exception
}

try...catch中为该异常提供外部RunMethod,以便更直接地中断处理。

但是,关闭标志可能更好地作为线程的信号处理,然后回滚任何挂起的事务和中止处理,而不必在每条指令之前检查状态。您还必须在数据库调用期间屏蔽信号。

当然,这取决于您的程序架构。

答案 3 :(得分:0)

如果您的Do功能返回了某些内容,那么您可以&amp;&amp;或||它们在一起,所以只要其中一个返回“假”或“真”,无论哪个是终止条件,你都会停止处理。

如果在操作期间(或者在执行它之前)由另一个线程设置了关闭标志会发生什么?如果你还是运行了这个过程会发生什么。

答案 4 :(得分:0)

您的标志用法将仅限于使用数据库的各种方法:DoSomethingOnDB,DoSomethingMoreOnDB ......

假设您正确使用互斥锁和锁(这里似乎没有),您可以将数据库相关的方法收集到复合方法中并在那里锁定数据库并在该单个方法中执行单个检查bool操作,以便只有一个线程一次做一个数据库操作。