Colderleo's blog Colderleo's blog
首页
Linux
C++
Python
前端
工具软件
mysql
索引
关于
GitHub (opens new window)

Colder Leo

热爱代码的打工人
首页
Linux
C++
Python
前端
工具软件
mysql
索引
关于
GitHub (opens new window)
  • bug定位的一些情形
  • c++性能调优,可能的情况
  • total-编程知识点集锦
  • hpc_common.hpp
  • memory order 内存模型
  • 类型推导之auto-template-decltype
  • 完美转发forward源码分析
  • 左值和右值,右值引用、重载 std-move,引用折叠
  • cmake用法
  • alignas、alignof、sizeof实现内存对齐分配
  • 通过宏定义控制debug打印
  • 程序耗时性能测试
  • 线程池开源项目阅读
  • C++类中包含没有默认构造函数的成员
  • C++可变参数模板
  • C++属性继承 public protected private
  • C++智能指针
  • C++导出so的方法,以及extern C 注意事项
  • 四种spin lock
  • condition_variable和unique_lock
    • c++11 condition_variable用法
    • pthreadcondt用法
    • LeetCode题目
    • uniquelock和lockguard
    • 生产者和消费者例子
  • dpdk、kernel bypass
  • 智能网卡solarflare、Mellanox、X10等
  • 汇编寄存器和常见指令
  • c++ 类的静态成员变量未定义
  • C++获取类成员函数地址
  • preload示例
  • C++异常安全和RAII
  • C++11单例模式
  • C++歪门邪道
  • boost-program-option用法
  • c++17通过模板获取类成员的个数
  • 通过模板实现结构体成员拷贝-按成员名匹配
  • STL学习路径
  • boost库安装使用方法
  • C++文件读写
  • linux下socket通信demo,server和client
  • makefile写法
  • RxCpp
  • C++
gaoliu
2021-10-06
目录

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

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

之所以把wait放在循环中,而不是用下面的if,一是为了防止虚假唤醒,二是防止被唤醒后条件依然不满足 (可能有其他竞争者,lock时被阻塞;或者notify的线程并没有生产资源使条件满足)。

if(!pred()) {
    cv.wait(lck); 
}
1
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

编译:

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

# 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
编辑 (opens new window)
上次更新: 2023/05/07, 17:27:54
四种spin lock
dpdk、kernel bypass

← 四种spin lock dpdk、kernel bypass→

最近更新
01
通过模板实现结构体成员拷贝-按成员名匹配
05-07
02
c++17通过模板获取类成员的个数
05-01
03
avx-sse切换惩罚
04-30
更多文章>
Theme by Vdoing | Copyright © 2019-2023 Colder Leo | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×