如何在 while 循环中使用条件变量进行互斥锁?
How to do mutex lock with a conditional variable in while loop?
我有两个函数,一个是 运行 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();
}
运行Forever 没有循环,我想一直循环直到调用关机。帮我解决这个问题。我非常感谢对此的任何线索和建议。
第 1 部分
我对您的程序进行了修改,使其现在可以运行。主要是我不得不制作 doStop_ = true;
而不是 doStop_ = false;
,因为根据英语程序的逻辑,当 do-stop 变为真时应该停止。
您还必须按照我在下面的代码中显示的方式放置互斥保护,即第一个锁在 while 循环之外,第二个标志设置锁的范围应该在通知调用之外。事实上,如果您将 wait
与谓词一起使用,您实际上不需要 while 循环,如 std docs.
中所述
这里是模拟工作过程:
#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 就足够了。 Atomic 允许立即传播 bool 变量的更改值。请参阅下面的代码:
#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
第 3 部分
您还可以与 atomic bool 一起在 while 循环中使用条件变量以将其用于暂停目的,而不是 std::this_thread::sleep_for()
。
条件变量将有助于停止前的最后一次迭代,将有助于在整个暂停完成之前提前终止。
您可以在下面的控制台输出示例中看到,与 第 2 部分 示例中的 1.2 sec
相比,服务器在 1.1 sec
处提前停止我的回答。
#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
我有两个函数,一个是 运行 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();
}
运行Forever 没有循环,我想一直循环直到调用关机。帮我解决这个问题。我非常感谢对此的任何线索和建议。
第 1 部分
我对您的程序进行了修改,使其现在可以运行。主要是我不得不制作 doStop_ = true;
而不是 doStop_ = false;
,因为根据英语程序的逻辑,当 do-stop 变为真时应该停止。
您还必须按照我在下面的代码中显示的方式放置互斥保护,即第一个锁在 while 循环之外,第二个标志设置锁的范围应该在通知调用之外。事实上,如果您将 wait
与谓词一起使用,您实际上不需要 while 循环,如 std docs.
这里是模拟工作过程:
#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 就足够了。 Atomic 允许立即传播 bool 变量的更改值。请参阅下面的代码:
#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
第 3 部分
您还可以与 atomic bool 一起在 while 循环中使用条件变量以将其用于暂停目的,而不是 std::this_thread::sleep_for()
。
条件变量将有助于停止前的最后一次迭代,将有助于在整个暂停完成之前提前终止。
您可以在下面的控制台输出示例中看到,与 第 2 部分 示例中的 1.2 sec
相比,服务器在 1.1 sec
处提前停止我的回答。
#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