c++11的function、(bind、lambda绑定回调)、std::thread使用示例

function与bind示例

function的作用就是把函数、函数对象、仿函数等统一封装成对象,取代函数指针,常用于回调,类似函数的多态(一个统一接口),对于解耦代码很友好。
而bind和lambda就是创建函数对象传给他的,如std::thread()就要传一个函数对象。(建议使用lambda,即可绑定匿名回调,游客调用函数间接实现绑定有名回调)

#include <iostream>
using namespace std::placeholders; //bind的命名空间
#include <functional>
class test {
public: 
    unordered_map<int, function<void(string b)>> map;
    void f1(int a, string b) {cout << a << b << endl;}
    void f2(int a, string b) {cout << a << b << endl;}
    test() {//bind的作用就是赋值给function<void(string b)>
        map[1] = std::bind(&test::f1, this, std::placeholders::_1, std::placeholders::_2);//占位
        map[2] = bind(&test::f2, this, std::placeholders::_1, "固定");//绑定固定值,后续就不用传该位置形参
        map[2] = [&](int a, string b){this->f2(a, b)};//使用lambda表达式绑定回调,&会捕捉到this指针,或者直接[this]也可以。
    }
};
int main(int argc, char* argv[]) {  
    test t;
    // 得到对应回调,直接执行,因为function重载了函数调用运算符(),这里其实就是多态的体现。
    t.map[atoi(argv[1])](argv[2]);
}

c++11线程库

c++11线程库:语言级别好处是跨平台,且不用-pthread

线程使用

#include <thread> 
std::thread t1(myfunc,2);这就是一个线程,且可传参
//或者用匿名函数
std::thread t([](int a){
		std::cout<< a << std::endl;
}, 2);
t1.detach();
//若是成员函数回调成员函数,就用lambda表达式:
class Test {
public:
    void func(int a) {
        std::thread t([&](){raft(a);}); //&捕获,捕获到了this指针,自然能使用类成员
        t.detach();
    }
private:
    void raft(int a) {}
};

c++20的jthread :自动join或detach

互斥锁

锁的本质就是只能指针,构造函数里加锁,析构函数里解锁,所以出作用域就解锁了
注意: c++11的mutex、cv、sem都不能用于进程间同步,若要进程间同步:pthread_mutex,参考操作系统-进程篇

#include <mutex>
std::mutex mtx;
{
	//省略了模板定义,因为c++17后都可以自动推导了,如std::vector v = {1};
	//但一般不省,锁这里省掉不影响可读性。
    std::unique_lock lock(mtx);//lock是锁名,出作用域自动解锁,也可手动加解锁或设置加锁超时时间
    std::lock_guard lock(mtx); //更轻量级,只能自动解锁,功能少。
    xxx
}

读写锁

读共享,写独占,适用于读多写少的场景

#include <shared_metex>
#include <mutex>
std::shared_metex sMtx;
{
	//获取读锁,自动解锁;若是想用数据,可以先把数据存下来,然后赶紧解锁。
	std::shared_lock lock(sMtx); 
	xxx;
}
{
	//获取写锁,自动解锁
	std::unique_lock lock(sMtx);  // 加写锁
	xxx
}
//也可手动加解锁,适合封装使用
std::shared_mutex rw_mtx;
rw_mtx.lock();			  //加写锁
rw_mtx.unlock();		  //释放写锁
rw_mtx.lock_shared(); 	  //加共享读锁
rw_mutex.unlock_shared(); //释放读锁

条件变量

配合锁使用,可参考C++线程池

#include <condition_variable> 
std::mutex mtx;
std::condition_variable cv;
{
	std::unique_lock lck(mtx); 
    //释放锁,等待notify
    cv.wait(lck);
    //释放锁,等待一定时间,超时自动醒
    cv_.wait_for(lock, std::chrono::milliseconds(connectTimeout_));
	//notify强制唤醒,满足条件也自动醒,
	cv.wait(lock, [&](){ return stop || !tasks.empty(); }); 	


    cv.notify_all();//强制唤醒所有线程,逐个获得锁
    cv.notify_one();//强制唤醒一个线程获得锁
}

信号量

c++20, 一般也是配合锁使用
信号量代表了资源的数量,如同时访问数据库的最大线程数。

#include <iostream>
#include <unistd.h>
#include <thread>
#include <semaphore>

//本例信号量代表:最多10个线程同时访问worker函数
std::counting_semaphore<10> sem(2); //<10>: 表示信号量的上限,(2): 初始化信号量数

void worker(int id) {
    sem.acquire();  //若sem>0,就获取,sem-1; 若sem=0, 就阻塞,直到sem>0
    std::cout << "Worker " << id << " is working." << std::endl;
    sleep(1);       // 模拟工作
    std::cout << "Worker " << id << " is done." << std::endl;
    sem.release();  // 释放, sem+1
}

int main() {
    std::thread t1(worker, 1);
    std::thread t2(worker, 2);
    std::thread t3(worker, 3);

    t1.join();
    t2.join();
    t3.join();
}

结果如图:
在这里插入图片描述
t1, t2是并发执行的,因为刚开始有2个信号量,而t3需要等他们release才获得sem。

原子类型

可以保证对单个变量操作的线程安全

#include <atomic>
//<T>只能是整数或指针
std::atomic<int> a;
std::atomic<Node*> p;
a++; //不用加锁
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值