参考cplusplus
参考cppreference
1.condition_variable
- 为std::unique_lock提供条件变量
1.1 wait/ wait_for / wait_until
//unconditional (1)
void wait (unique_lock& lck);
//predicate (2)
template
void wait (unique_lock& lck, Predicate pred);
- 条件变量工作过程:
step1.调用者把锁住的lck传给函数,函数然后自动把线程放到等待条件的线程列表上,然后对lck进行解锁。
step2.一旦条件变量满足,wait返回时,函数解除阻塞,病重新多lck进行加锁。
如果指定了谓词pred,函数只在pred为false才阻塞,并且通知只有在pred为true的时候才能解除阻塞。
// condition_variable::wait (with predicate)
#include // std::cout
#include // std::thread, std::this_thread::yield
#include // std::mutex, std::unique_lock
#include // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
int cargo = 0;
bool shipment_available() {return cargo!=0;}
void consume (int n) {
for (int i=0; i lck(mtx);
cv.wait(lck,shipment_available);
// consume:
std::cout << cargo << '\n';
cargo=0;
}
}
int main ()
{
std::thread consumer_thread (consume,10);
// produce 10 items when needed:
for (int i=0; i<10; ++i) {
while (shipment_available()) std::this_thread::yield();
std::unique_lock lck(mtx);
cargo = i+1;
cv.notify_one();
}
consumer_thread.join();
return 0;
}
//unconditional (1)
template
cv_status wait_for (unique_lock& lck,
const chrono::duration& rel_time);
//predicate (2)
template
bool wait_for (unique_lock& lck,
const chrono::duration& rel_time, Predicate pred);
- 版本1返回 cv_status::timeout或者cv_status::no_timeout;
版本2返回pred()
// condition_variable::wait_for example
#include // std::cout
#include // std::thread
#include // std::chrono::seconds
#include // std::mutex, std::unique_lock
#include // std::condition_variable, std::cv_status
std::condition_variable cv;
int value;
void read_value() {
std::cin >> value;
cv.notify_one();
}
int main ()
{
std::cout << "Please, enter an integer (I'll be printing dots): \n";
std::thread th (read_value);
std::mutex mtx;
std::unique_lock lck(mtx);
while (cv.wait_for(lck,std::chrono::seconds(1))==std::cv_status::timeout) {
std::cout << '.' << std::endl;
}
std::cout << "You entered: " << value << '\n';
th.join();
return 0;
}
//unconditional (1)
template
cv_status wait_until (unique_lock& lck,
const chrono::time_point& abs_time);
//predicate (2)
template
bool wait_until (unique_lock& lck,
const chrono::time_point& abs_time,
Predicate pred);
1.2 notify_one / notify_all
void notify_one() noexcept;
- 将等待该条件的一个线程取消阻塞。多余一个线程等待时,选择哪个线程是未指定的。
// condition_variable::notify_one
#include // std::cout
#include // std::thread
#include // std::mutex, std::unique_lock
#include // std::condition_variable
std::mutex mtx;
std::condition_variable produce,consume;
int cargo = 0; // shared value by producers and consumers
void consumer () {
std::unique_lock lck(mtx);
while (cargo==0) consume.wait(lck);
std::cout << cargo << '\n';
cargo=0;
produce.notify_one();
}
void producer (int id) {
std::unique_lock lck(mtx);
while (cargo!=0) produce.wait(lck);
cargo = id;
consume.notify_one();
}
int main ()
{
std::thread consumers[10],producers[10];
// spawn 10 consumers and 10 producers:
for (int i=0; i<10; ++i) {
consumers[i] = std::thread(consumer);
producers[i] = std::thread(producer,i+1);
}
// join them back:
for (int i=0; i<10; ++i) {
producers[i].join();
consumers[i].join();
}
return 0;
}
void notify_all() noexcept;
// condition_variable::notify_all
#include // std::cout
#include // std::thread
#include // std::mutex, std::unique_lock
#include // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id (int id) {
std::unique_lock lck(mtx);
while (!ready) cv.wait(lck);
// ...
std::cout << "thread " << id << '\n';
}
void go() {
std::unique_lock lck(mtx);
ready = true;
cv.notify_all();
}
int main ()
{
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(print_id,i);
std::cout << "10 threads ready to race...\n";
go(); // go!
for (auto& th : threads) th.join();
return 0;
}
2.condition_variable_any
- 为任何的lock类型提供条件变量
//unconditional (1)
template void wait (Lock& lck);
//predicate (2)
template
void wait (Lock& lck, Predicate pred);
// condition_variable_any::notify_all
#include // std::cout
#include // std::thread
#include // std::mutex
#include // std::condition_variable_any
std::mutex mtx;
std::condition_variable_any cv;
bool ready = false;
void print_id (int id) {
mtx.lock();
while (!ready) cv.wait(mtx);
// ...
std::cout << "thread " << id << '\n';
mtx.unlock();
}
void go() {
mtx.lock();
ready = true;
cv.notify_all();
mtx.unlock();
}
int main ()
{
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(print_id,i);
std::cout << "10 threads ready to race...\n";
go(); // go!
for (auto& th : threads) th.join();
return 0;
}
3.notify_all_at_thread_exit
void notify_all_at_thread_exit (condition_variable& cond, unique_lock lck);
- lck最好是右值
在线程退出的时候类似于做了一下工作:
lck.unlock();
cond.notify_all()
// notify_all_at_thread_exit
#include // std::cout
#include // std::thread
#include // std::mutex, std::unique_lock
#include // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id (int id) {
std::unique_lock lck(mtx);
while (!ready) cv.wait(lck);
// ...
std::cout << "thread " << id << '\n';
}
void go() {
std::unique_lock lck(mtx);
std::notify_all_at_thread_exit(cv,std::move(lck));
ready = true;
}
int main ()
{
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(print_id,i);
std::cout << "10 threads ready to race...\n";
std::thread(go).detach(); // go!
for (auto& th : threads) th.join();
return 0;
}
4.cv_status——前面有用到
enum class cv_status { no_timeout, timeout };