【问题标题】:Synchronization of 2 threads, how to?2个线程的同步,怎么做?
【发布时间】:2016-01-31 12:21:44
【问题描述】:

我正在尝试开发一个 C++ 软件,它有 1 个线程作为控制器(比如控制器)和 8 个其他线程(子线程)将通过 TCP/IP 进行发送/接收。

我的软件是循环运行的:

  • 一开始,子线程无限循环运行,在循环中等待来自控制器的 START 信号。如果它们被来自控制器的信号唤醒,它们将执行发送/接收过程。发出信号后,控制器将等待来自子线程的停止信号。
  • 在完成发送/接收后,它们每个都会向控制器发送一个停止信号。如果控制器接收到足够的停止信号(8 个子线程的 8 个停止信号)。它将复制数据,然后再次启动该过程(下一个循环)。

为此,我从一个非常基本的步骤开始我的软件:控制器线程和一个子线程,而这个子线程不做任何事情。 (如果一切正常,我会继续前进):

  • 换句话说,控制器在子线程等待时向子线程发送 START 信号。
  • 子线程收到 START 信号后立即发回 STOP 信号。

我先运行这个软件1000次,有时候效果很好,有时候不行,经常死机。

我想知道为什么会这样。

为了更好的解释,请参考我的代码:

#include "CxxUtilities/CxxUtilities.hh"
using namespace std;
CxxUtilities::Condition StartSignal;
CxxUtilities::Condition StopSignal;

// declare a class of tx_thread, open, alive, wait for signal from controller thread //
class ChildThread: public CxxUtilities::StoppableThread{
public:
  void run(){
    cout << "started tx_thread" << endl;
        while(!stopped){

      /* wait for signal from main thread */
      cout << "sub:wait for main...";
      StartSignal.wait();
      cout << "sub:done, \n";

      /* signal to main thread */
      StopSignal.signal();     
      cout << "sub:signal sent, \n";
    }

  }

};

int main(int argc, char* argv[]) {
    using namespace CxxUtilities;
    int i;
    int Events = atoi(argv[1]);

    // declear threads //
    ReadingThread* thread[20];
    thread[0] = new ReadingThread;
    thread[0]->start();
    usleep(1000);

    for (i=0; i<Events; i++){
      cout << "\nevent#" << i+1 << ", ";
      /* send start signal to sub thread */
      StartSignal.broadcast();
      cout << "main:signal sent, \n";

      /* wait for stop signal from sub thread */
       cout << "main:wait for sub ...";
      StopSignal.wait();      
      cout << "main:done, \n";
    }
    cout << endl;
}

如果我将此软件修改为仅向子线程发出控制器信号或仅向控制器发出子线程信号,则它可以正常工作。 当我们使用来自 2 个 trheads 的 2 个信号时,您对为什么线程冻结有任何想法吗?

在这个软件中,有两个头文件被用到,分别是Thread.hhCondition.hh

这里是Condition.hh头文件中singal()和wait()的一部分:

   void signal(){
    mutex.lock();
    pthread_cond_signal(&condition);
    mutex.unlock();

    void wait(){
    mutex.lock();
    pthread_cond_wait(&condition,mutex.getPthread_Mutex_T());
    mutex.unlock();
}

【问题讨论】:

    标签: c++ multithreading


    【解决方案1】:

    由于死锁而冻结。可能发生这种情况的一种方法是,如果主调用StopSignal.wait,并在设置条件之前锁定互斥锁。然后你的子线程调用StopSignal.signal,它会阻塞等待互斥锁。因此,两个线程都被阻塞,等待对方采取行动。

    应在最短的时间内获取锁。在拥有锁的同时执行等待是自找麻烦。您需要对其进行重组,以便等待没有锁。类似的东西

    for (;;) {
        mutex.lock();
        bool done = /*check condition variable*/;
        mutex.unlock();
        if (done) break;
        sleep(1);
    }
    

    这将在您访问受保护的条件变量时保持锁定,然后在您检查条件结果时释放它(允许其他线程访问条件)。睡眠是为了释放 CPU 资源。

    这不是解决问题的唯一方法,但实现起来非常简单。

    【讨论】:

    • 对不起,我对你的解释感到困惑......让我用我的理解解释一下: - 主线程在子线程调用signal()之前阻止互斥体调用wait()? - 正因为如此,互斥体被锁定在主线程中,子线程无法锁定互斥体来调用signal()?
    • @KhảiBùiTuấn 没错。由于主线程获得了互斥锁,子线程阻塞(等待)互斥锁。
    • 亲爱的@1201ProgramAlarm,您的意思是我们必须在 wait() 之前发出 signal() 吗?如果是这样,我认为这没有道理吗?这里也提到了[link](computing.llnl.gov/tutorials/pthreads/#ConditionVariables)在调用pthread_cond_wait()之前调用pthread_cond_signal()是一个逻辑错误。
    • 亲爱的,现在,我真的很困惑,对不起,但我想你的评论也许是对的。但也许我也有一些误解。比如说,要调用 wait() 和 signal(),我们必须先调用 mutex.lock()。但是如果 wait() 在此之前发生,则互斥锁不是 unlock(),因此 signal() 不会发生。但是我们也必须在调用 signal() 之前调用 wait() 对吗?
    • 亲爱的,我找到了前面评论的答案 pthread_cond_wait() 会阻塞调用线程,直到发出指定条件的信号。该例程应该在互斥锁被锁定时调用,它会在等待时自动释放互斥锁。收到信号并唤醒线程后,互斥量将自动锁定以供线程使用。然后,程序员负责在线程完成后解锁互斥锁。
    猜你喜欢
    • 2011-04-05
    • 2019-01-28
    • 2023-03-13
    • 2013-09-12
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    • 2017-10-06
    • 1970-01-01
    相关资源
    最近更新 更多