c++ - 如何在 while 循环中使用条件变量进行互斥锁?

标签 c++ while-loop c++17 mutex

我有两个函数,一个是运行serveRunForever,另一个是shutDown。

Server::runForever ()
{
while(!doStop_)
{
unique_lock<mutex> lck(stop);
//Do something, it should be looping in while loop
CV.wait(lck, [this]() {return doStop_;});
}

上面不是循环它开始在 CV.wait() 中等待。

Server::shutDown()
{
scoped_lock lck(stop);
doStop_ = true;
CV.notify_one();
}

runForever 不在 while 中循环,我想连续循环直到调用关闭。帮我解决这个问题。我非常感谢对此的任何线索和建议。

最佳答案

第 1 部分

我对您的程序进行了修改,使其现在可以运行。主要是我必须使用 doStop_ = true; 而不是 doStop_ = false;,因为根据英语程序的逻辑,当 do-stop 变为 true 时应该停止。

此外,您还必须按照我在下面的代码中所示的方式放置互斥锁,即第一个锁位于 while 循环之外,第二个标志设置锁的范围应位于通知调用之外。事实上,如果您将 wait 与谓词一起使用,则实际上不需要 while 循环,如 std docs 中所述。 .

下面是工作过程的模拟:

Try it online!

#include <condition_variable>
#include <thread>
#include <mutex>
#include <iostream>
#include <chrono>

class Server {
public:
    void runForever();
    void shutDown();
private:
    std::condition_variable CV;
    std::mutex stop;
    bool doStop_ = false;
};

void Server::runForever() {
    std::unique_lock<std::mutex> lck(stop);
    while (!doStop_)
        CV.wait(lck, [this]() { return doStop_; });
}

void Server::shutDown() {
    {
        std::lock_guard<std::mutex> lck(stop);
        doStop_ = true;
    }
    CV.notify_one();
}

int main() {
    auto const time_begin = std::chrono::high_resolution_clock::now();
    auto TimeElapsed = [&]{
        return double(std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::high_resolution_clock::now() - time_begin).count()) / 1000;
    };

    Server server;
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    std::thread t0([&]{
        std::cout << "Server started at " << TimeElapsed() << " sec" << std::endl;
        server.runForever();
        std::cout << "Server stopped at " << TimeElapsed() << " sec" << std::endl;
    });
    std::this_thread::sleep_for(std::chrono::milliseconds(1500));
    server.shutDown();
    t0.join();
}

输出:

Server started at 0.2 sec
Server stopped at 1.7 sec

第 2 部分

如果您需要在 while 循环内进行一些计算,而不仅仅是等待,那么条件变量不适合您。您应该使用 std::atomic bool相反,或者只是普通的 bool 值也几乎足够了。原子允许立即传播 bool 变量的更改值。请参阅下面的代码:

Try it online!

#include <atomic>
#include <thread>
#include <mutex>
#include <iostream>
#include <chrono>

class Server {
public:
    void runForever();
    void shutDown();
private:
    std::atomic<bool> doStop_ = false;
};

void Server::runForever() {
    while (!doStop_) {
        std::cout << "Doing computation..." << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
    }
}

void Server::shutDown() {
    doStop_ = true;
}

int main() {
    auto const time_begin = std::chrono::high_resolution_clock::now();
    auto TimeElapsed = [&]{
        return double(std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::high_resolution_clock::now() - time_begin).count()) / 1000;
    };

    Server server;
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    std::thread t0([&]{
        std::cout << "Server started at " << TimeElapsed() << " sec" << std::endl;
        server.runForever();
        std::cout << "Server stopped at " << TimeElapsed() << " sec" << std::endl;
    });
    std::this_thread::sleep_for(std::chrono::milliseconds(900));
    server.shutDown();
    t0.join();
}

输出:

Server started at 0.21 sec
Doing computation...
Doing computation...
Doing computation...
Doing computation...
Doing computation...
Server stopped at 1.21 sec

第三部分

还可以与atomic bool一起使用while循环内的条件变量来将其用于暂停目的,而不是std::this_thread::sleep_for()

条件变量将有助于停止前的最后一次迭代,有助于在整个暂停完成之前提前终止。

您可以在下面的控制台输出示例中看到,与第 2 部分示例中的 1.2 秒 相比,服务器在 1.1 秒 处提前停止强>我的回答。

Try it online!

#include <condition_variable>
#include <atomic>
#include <thread>
#include <mutex>
#include <iostream>
#include <chrono>

class Server {
public:
    void runForever();
    void shutDown();
private:
    std::atomic<bool> doStop_ = false;
    std::mutex mutex_;
    std::condition_variable CV;
};

void Server::runForever() {
    while (!doStop_) {
        std::cout << "Doing computation..." << std::endl;
        
        std::unique_lock<std::mutex> lck(mutex_);
        CV.wait_for(lck, std::chrono::milliseconds(200),
            [this]{ return bool(doStop_); });
    }
}

void Server::shutDown() {
    {
        std::lock_guard<std::mutex> lck(mutex_);
        doStop_ = true;
    }
    CV.notify_all();
}

int main() {
    auto const time_begin = std::chrono::high_resolution_clock::now();
    auto TimeElapsed = [&]{
        return double(std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::high_resolution_clock::now() - time_begin).count()) / 1000;
    };

    Server server;
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    std::thread t0([&]{
        std::cout << "Server started at " << TimeElapsed() << " sec" << std::endl;
        server.runForever();
        std::cout << "Server stopped at " << TimeElapsed() << " sec" << std::endl;
    });
    std::this_thread::sleep_for(std::chrono::milliseconds(900));
    server.shutDown();
    t0.join();
}

输出:

Server started at 0.203 sec
Doing computation...
Doing computation...
Doing computation...
Doing computation...
Doing computation...
Server stopped at 1.1 sec

关于c++ - 如何在 while 循环中使用条件变量进行互斥锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69971693/

相关文章:

c++ - 为什么条件变量会固定我们的功耗?

c++ - 为什么我必须按两次 Enter 才能使用 Netbeans 7.3.1 和最新的 MinGW 工具集执行 cin 语句?

c++ - 警告 : 'struct curl_fileinfo' declared inside parameter list

php - 使用 PHP SQL 在数据库中查找特定值

java - Java 回文 : While and If/Else Statements

C++ 模板 "if constexpr"转换为旧的 "Tag Dispatching"方法

c++ - `if constexpr`,lambda 内部,包扩展内部——编译器错误?

c++ - cpp 核心指南中的 owner<T*> p 语法

c++ - std::promise set_exception 两次导致段错误

java - while 循环中的条件