conditionvariable和uniquelock
# c++11 condition_variable用法
https://blog.csdn.net/liu3612162/article/details/88343266
condition_variable使用时有以下两种写法
//pred是callable,判断条件是否成立
cv.wait(lck, pred);
//等同于下面的写法
while (!pred()) //如果不满足pred()
{
cv.wait(lck); //那么继续等待。
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
wait(lck) 展开,等同于执行下面的代码:
while (!pred()) //如果不满足pred()
{
//cv.wait(lck)展开:
release(lck); //释放锁
blocked_waiting_for_notiry(); //挂起线程,等待其他线程调用cv.notify时才被激活。这里也有可能被虚假唤醒。
lock(lck); //再次尝试加锁,注意此时可能会被再次阻塞。
}
1
2
3
4
5
6
7
2
3
4
5
6
7
之所以把wait放在循环中,而不是用下面的if,一是为了防止虚假唤醒,二是防止被唤醒后条件依然不满足 (可能有其他竞争者,lock时被阻塞;或者notify的线程并没有生产资源使条件满足)。
if(!pred()) {
cv.wait(lck);
}
1
2
3
2
3
https://www.jianshu.com/p/c1dfa1d40f53
# pthread_cond_t用法
参考: https://blog.csdn.net/chengonghao/article/details/51779279
c++11中的condition_variable是对pthread_cond_t做了一个封装,原理一样的。
/***************************************************************
* Copyright (C) 2016 chengonghao
* All rights reserved.
*
* chengonghao@yeah.net
***************************************************************/
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#define CONSUMERS_COUNT 2
#define PRODUCERS_COUNT 1
pthread_mutex_t g_mutex;
pthread_cond_t g_cond;
pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT];
int share_variable = 0; // this is the share variable, shared by consumer and producer
void *consumer(void *arg)
{
size_t num = (size_t)arg;
while (1)
{
/******* critical section begin *******/
pthread_mutex_lock(&g_mutex);
// if share_variable == 0, means consumer shell stop here
while (share_variable == 0)
{
printf("consumer %u begin wait a condition...\n", num);
// put a thread blocked ont a condition variable( here is g_cond),
// and unlock the mutex( here is g_mutex )
pthread_cond_wait(&g_cond, &g_mutex);
}
// here means n != 0 and consumer can goes on
// consumer consumed shared variable, so the number of shared variable shell minus
printf("consumer %u end wait a condition...\n", num);
printf("consumer %u begin consume product\n", num);
--share_variable;
pthread_mutex_unlock(&g_mutex);
/******** critial section end *********/
sleep(1);
}
return NULL;
}
void *producer(void *arg)
{
size_t num = (size_t)arg;
while (1)
{
/******* critical section begin *******/
pthread_mutex_lock(&g_mutex);
// produce a shared variable
printf("producer %u begin produce product...\n", num);
++share_variable;
printf("producer %u end produce product...\n", num);
// unblock threads blocked on a condition variable( here is g_cond )
pthread_cond_signal(&g_cond);
printf("producer %u notified consumer by condition variable...\n", num);
pthread_mutex_unlock(&g_mutex);
/******** critial section end *********/
sleep(5);
}
return NULL; //1
}
int main(void)
{
// initiate mutex
pthread_mutex_init(&g_mutex, NULL);
// initiate condition
pthread_cond_init(&g_cond, NULL);
// initiate consumer threads
for (int i = 0; i < CONSUMERS_COUNT; ++i)
{
pthread_create(&g_thread[i], NULL, consumer, (void *)i);
}
sleep(1);
// initiate producer threads
for (int i = 0; i < PRODUCERS_COUNT; ++i)
{
pthread_create(&g_thread[i], NULL, producer, (void *)i);
}
for (int i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; ++i)
{
pthread_join(g_thread[i], NULL);
}
pthread_mutex_destroy(&g_mutex);
pthread_cond_destroy(&g_cond);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
编译:
gcc condition_test.c -o test –lpthread
1
# LeetCode题目
https://leetcode-cn.com/problems/print-in-order/solution/cpp-beats-100-shi-yong-tiao-jian-bian-liang-by-geo/
#include <iostream>
#include <string>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <thread>
using namespace std;
class Foo {
private:
int counter = 1;
std::condition_variable cv1, cv2;
// 使用lock和unlock手动加锁
std::mutex g_mutex;
public:
Foo() {}
public:
void first() {
// 等待直至 main() 发送数据
std::unique_lock<std::mutex> lk(g_mutex);
printf("print first.\n");
// 通知前完成手动解锁,以避免等待线程才被唤醒就阻塞(细节见 notify_one )
counter++;
cv1.notify_one();
}
void second() {
std::unique_lock<std::mutex> lk(g_mutex);
cv1.wait(lk, [this]() {return counter == 2; }); // 阻塞当前线程,直到条件变量被唤醒
printf("print second.\n");
counter++;
cv2.notify_one();
}
void third() {
std::unique_lock<std::mutex> lk(g_mutex);
cv2.wait(lk, [this]() {return counter == 3; });
printf("print thrid.\n");
}
};
int main()
{
Foo f;
thread t2(&Foo::second, &f);
thread t3(&Foo::third, &f);
thread t1(&Foo::first, &f);
t1.join();
t2.join();
t3.join();
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# unique_lock和lock_guard
https://www.cnblogs.com/xudong-bupt/p/9194394.html
# 生产者和消费者例子
#include<thread>
#include<mutex>
#include<condition_variable>
#include<iostream>
#include<vector>
using namespace std;
int cargo = 0;
mutex g_mutex;
condition_variable cv_consumer, cv_producer;
bool consumer_exit = false;
void consumer(int thread_index) {
this_thread::sleep_for(chrono::milliseconds(1000));
while (true) {
this_thread::sleep_for(chrono::milliseconds(rand() % 300)); // simulate porcessing goods.
unique_lock<mutex> lck(g_mutex); //acquire lock befor modify cargo.
cv_consumer.wait(lck, []() {return (cargo > 0 || consumer_exit); });
cout << thread_index <<" get lock" << endl;
if (consumer_exit) {
cout <<"thread "<<thread_index <<" exit" << endl;
lck.unlock();
cv_consumer.notify_one();
break;
}
cargo--;
cout <<"thread " << thread_index << " consume 1 goods, current goods: " << cargo << endl;
lck.unlock(); //release lock to let other thread run.
cout << thread_index << " release lock" <<endl;
if (!cargo)
cv_producer.notify_one();
else
cv_consumer.notify_one();
this_thread::sleep_for(chrono::milliseconds(200)); // simulate porcessing goods.
}
//cout << "thread " << thread_index << " end" << endl;
}
void deamon() {
// in case all threads are sleep and notify is ignored, periodly notify to wake up.
while (!consumer_exit) {
this_thread::sleep_for(chrono::seconds(3));
cv_consumer.notify_one();
cv_producer.notify_one();
cout << "current goods : " << cargo << endl;
if (g_mutex.try_lock()) {
cout << "mutex is avaliable" << endl;
g_mutex.unlock();
}
else {
cout << "mutex is unavaliable" << endl;
}
}
this_thread::sleep_for(chrono::seconds(3));
cv_consumer.notify_one();
cv_producer.notify_one();
}
int main() {
vector<thread> vec;
thread t_deamon = thread(deamon);
for (int i = 0; i < 3; ++i) {
thread t = thread(consumer, i);
vec.emplace_back(move(t));
}
for (int i = 0; i < 2; ++i) {
unique_lock<mutex> lck(g_mutex);
cv_producer.wait(lck, []() {return (cargo == 0); });
cout << "main get lock" << endl;
cargo += 5;
cout << "produce goods " << (i+1)*5 <<" current goods: "<< cargo << endl;
lck.unlock();
cout << "main release lock" << endl;
cv_consumer.notify_one();
this_thread::sleep_for(chrono::milliseconds(rand() % 2000)); //simulate producing.
}
while (cargo > 0) {
this_thread::sleep_for(chrono::seconds(1));
}
consumer_exit = true;
cout << "produce end" << endl;
cv_consumer.notify_one();
for (auto &t : vec) {
t.join();
}
t_deamon.join();
cout << "main end" << endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
编辑 (opens new window)
上次更新: 2023/05/07, 17:27:54