0

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

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

那么,有没有其他方法可以在不发送大量 if 的情况下处理关机?

4

5 回答 5

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();
  }
于 2013-04-11T11:54:04.763 回答
1

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

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

在您更直接的中断处理try...catch中使用该异常的外部。RunMethod

然而,关闭标志也许可以更好地处理为线程的信号,然后回滚任何待处理的事务并中止处理,而不必在每条指令之前检查状态。您还必须在 DB 调用期间屏蔽信号。

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

于 2013-04-11T12:14:28.727 回答
1

您的应用程序中是否已经有 ReaderWriter 锁?您应该将数据库关闭视为写入操作,并在启动之前获取写入器锁。然后,一旦关闭正在进行,其他读取(获得读取器锁)或写入操作(获得写入器锁)都无法启动。

于 2013-04-11T11:58:47.837 回答
0

如果你的 Do 函数返回了一些你可以然后 && 或 || 将它们放在一起,以便一旦其中一个返回“false”或“true”(无论哪个是终止条件),您将停止处理。

如果在您的操作期间(或在执行它之前?)由不同的线程设置关闭标志会发生什么,如果您仍然运行此过程会发生什么。

于 2013-04-11T11:55:25.367 回答
0

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

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

于 2013-04-11T12:09:17.220 回答