c++多线程

子线程开启、互斥变量、条件变量

std::thread 用于开启一个线程。

参考

作用

std::thread 用于开启一个子线程。

举例:

void threadfunc()
{
    printf("sub thread\n");
}

int main(int argc, const char * argv[])
{
    std::thread th(threadfunc);
    //th.join();
    th.detach();
    return 0;
}

解释

上面的代码中 std::thread th(threadfunc) 开启了一个子线程。子线程的主函数是 threadfunc().

线程开启后,必须 join() 或者 detach() 否则会出现 th 这个变量退出作用域,被析构时,会报异常。

join() 的含义是,主线程必须等到这个子线程执行结束,才能继续。子线程结束之前,主线程会卡死在 th.join() 这一行。

detach() 的含义是,此线程与 th 这个变量毫无关联。这时,如果 th 变量析构后,不影响子线程的执行。并且 detach() 之后,主线程、子线程交替执行,两个线程之间没有先后关系。

std::mutex 互斥锁

作用

防止不同线程间的代码在不同线程间做不安全的切换

作用分析:mutex mtx,会定义一个变量mtx,如果mtx上锁了,即lock(),则多个线程在同一时刻仅上锁线程可以调用mtx,别的线程不能调用,只能在mtx处停止,等待mtx解锁。

举例

例如,一个子线一直往数组 std::vector arr 里插入元素,主线程一直从数组里删除元素。两个线程同时涉及修改 arr 变量。为了防止线程不同步,两个线程在各自操作 arr变量前,需要声明一个 std::mutex 变量,用 lock() unlock() 把关键的代码包围起来。

#include <stdio.h>
#include <thread>
#include <mutex>
#include <vector>

std::mutex mtx;
std::vector<int> arr;

void threadfunc()
{
    while(true)
    {
        mtx.lock();
        arr.push_back(3);
        mtx.unlock();
    }
}

int main(int argc, const char * argv[])
{
    std::thread th(threadfunc);
    th.detach();
    
    
    while(true)
    {
        mtx.lock();
        if(arr.size() > 0) {
            arr.erase(arr.begin());
        }
        mtx.unlock();
    }
    return 0;
}

解释

mutex 的 lock() 函数是会阻塞线程的。如果在 lock() 时,该 mutex 已经被其他线程调用了 lock,则此时会将线程卡死在 lock() 函数调用的位置,直到其他线程 unlock() 释放了 mutex ,这个线程才能继续执行。

条件std::condition_variable con

参考

作用

唤醒作用于process线程中的获取观测值数据的函数

  • 场景:线程1正在执行锁,线程2正在等待线程1解锁。那么线程2可以开启等待wait,线程1在解锁时可以调佣命令唤醒线程2,即:
  • 线程1:当该线程执行完程序并unlock后,可以开启 con.notify_one(),用来唤醒wait()线程。
  • 线程2:在等待时,线程2应该先解锁mutex,然后wait(),在被唤醒之后,wait()结束,然后使用mutex的lock进行上锁,然后执行程序,执行完毕后,进行解锁。
    • 首先使用std::unique_lock管理互斥锁,保证在wait()时,mutex的锁是解锁状态
    • 然后,调用wait()函数等待被唤醒。该函数可以添加λ表示,当返回true时才解锁。
    • 唤醒后由于unique_lock在管理互斥锁,所以可以自动上锁。
      • 最后就可以执行代码段,执行完毕之后,需手动调用互斥锁管理器中的unlock进行解锁。

举例

#include <iostream>
#include <deque>
#include <thread>
#include <mutex>
#include <condition_variable>

std::deque<int> q;						//双端队列标准容器全局变量
std::mutex mu;							//互斥锁全局变量
std::condition_variable cond;           //全局条件变量

//生产者,往队列放入数据
void function_1() {
    int count = 10;
    while (count > 0) {
        // 对互斥量mu上锁
        mu.lock();

        q.push_front(count);	//数据入队锁保护

        // 对互斥量mu解锁
        mu.unlock();

        // 向一个等待线程发出“条件已满足”的通知
        cond.notify_one();              
        
        std::this_thread::sleep_for(std::chrono::seconds(1));		//延时1秒
        count--;
    }
}
//消费者,从队列提取数据
void function_2() {
    int data = 0;
    while ( data != 1) {
        // 定义一个互斥锁管理器
        std::unique_lock<std::mutex> aa(mu);

        // wait()表示解锁互斥量并陷入休眠以等待通知被唤醒,被唤醒后自动加锁以保护共享数据
        // wait(),前部分是等待被唤醒,后面是λ表达式,判断队列是否为空,都满足才解除休眠
        cond.wait(aa, []{return !q.empty();}); 

        data = q.back();   
        q.pop_back();    //数据出队
        
        // 使用unique_locd进行 解锁
        aa.unlock();
        std::cout << "t2 got a value from t1: " << data << std::endl;
    }
}

int main() {
    std::thread t1(function_1);
    std::thread t2(function_2);
    t1.join();
    t2.join();

    getchar();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值