【问题标题】:Start and Stop a loop within a Thread in C++在 C++ 中的线程内启动和停止循环
【发布时间】:2012-08-17 14:44:01
【问题描述】:

我需要从一个事件开始循环,然后从另一个事件停止它。 我的想法是当我按下按钮时调用函数 startDequeuing(),以便启动一个带有循环的线程,然后终止这个循环,将函数 stopDequeuing() 中的“出队”变量设置为 false。

这是我第一次使用线程,当我开始循环时程序会锁定,我认为是因为变量“出队”被锁定并且无法从线程外部访问,对吗?

我该如何解决这个问题??

这里有一些代码:

void CameraManager::startDequeuing(){
    dequeuing = true;
    std::thread dequeueThread(&CameraManager::dequeueLoop, this);
    dequeueThread.join();
}

void CameraManager::stopDequeuing(){
    dequeuing = false;
}

void *CameraManager::dequeueLoop(){
    while(dequeuing){
        highSpeedCamera->dequeue();
        highSpeedCamera->enqueue();
    }
}

【问题讨论】:

  • 不,请不要使用 volatile,当它涉及到多线程时。它可能有效,但在正确编写的多线程应用程序中永远不需要它。这里的问题很可能是 stopDequeuing() 永远不会被调用,因为 startDequeing() 在 join() 上阻塞。

标签: c++ multithreading loops c++11 stdthread


【解决方案1】:

使用线程的全部意义在于让多个函数并行运行。这里:

std::thread dequeueThread(&CameraManager::dequeueLoop, this);
dequeueThread.join();

您启动第二个线程并让第一个线程进入睡眠状态,等待生成的线程返回。所以你仍然只有一个线程在运行。如果您有这种 GUI 事件循环,您可能会锁定添加回调的可能性,当该事件循环为空时,该回调将被调用。这可能使您可以在不使用线程的情况下做您想做的事情。

解决方案可能如下所示:

void CameraManager::startDequeuing(){
    dequeuing = true;
    dequeueThread = std::thread(&CameraManager::dequeueLoop, this);
}

void CameraManager::stopDequeuing(){
    {
        std::lock_guard<std::mutex> lock( mutex );
        dequeuing = false;
    }
    dequeueThread.join();
}

bool CameraManager::keepOnDequeuing()
{
    std::lock_guard<std::mutex> lock( mutex );
    return dequeuing;
}

void *CameraManager::dequeueLoop(){
    while( keepOnDequeuing() ){
        highSpeedCamera->dequeue();
        highSpeedCamera->enqueue();
    }
}

【讨论】:

  • 您在startDequeing 中缺少一个锁 - 如果您在startstop 中有锁,为什么要为keepOnDequeuing 添加keepOnDequeuing justdequeueLoop而不是那里的另一个锁?另外,您的线程仍然在startDequeuing 的范围内?!
  • @Dave 在启动线程之前没有锁定互斥锁是可以的,因为线程保证在线程启动之前看到对内存所做的更改。我添加了 keepOnDequeuing() 来制作 mutex.lock();读取标志; mutex.unlock() 更具可读性。尝试在没有那个帮助器的情况下编写 dequeueLoop() ,你会明白我的意思;-) lock_guard 将互斥锁锁定在它的 c'tor 中并在它的 d'tor 中解锁它,所以当名为 lock 的局部变量超出范围时,互斥锁已解锁()。
  • 如果您不创建一个立即死亡的线程,您将需要互斥锁。而且,我知道 lock_guard 做什么,我没有问。
  • @Dave,没有创建线程,立即死亡。临时线程变量只是意味着你不能再指向那个线程,所以你不能 join() 例如。但是你是对的,dequeueThread 必须有一个成员变量,并且启动线程应该是 `dequeueThread = std::thread(&CameraManager::dequeueLoop, this);'
  • 谢谢大家!我首先实现了 Torsten 提出的解决方案,当然将“dequeueThread”声明为一个类变量,并且效果很好!现在正如 Pete Becker 所建议的那样,我正在尝试使用 atomic bool 来提高性能。
【解决方案2】:

你的程序死锁是因为join() 会阻塞直到你的线程函数完成;而且它永远不会在那个时候完成,因为它正在有效地执行while(true)

您希望dequeueThread 成为您班级的成员。为什么你希望它只在startDequeuing 的范围内存活?

【讨论】:

    【解决方案3】:

    dequeing 定义为原子布尔值:

    #include <atomic>
    std::atomic_bool dequeing = false;
    

    它比使用互斥锁要快得多,并且可以获得相同的同步。

    【讨论】:

    • 忘了说:std::atomic_bool也可以拼成std::atomic&lt;bool&gt;
    猜你喜欢
    • 2018-01-04
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-16
    • 1970-01-01
    相关资源
    最近更新 更多