C++11之线程

编译环境:Qt

join:阻塞当前线程,直到线程函数退出

detach:将线程对象与线程函数分离,线程不依赖线程对象管理

注:join和detach两者必选其一,否则线程对象的回收会影响线程的回收,导致程序崩溃

思考:执行detach之后的线程如何退出?

  • 方法:设置标志位 
#include "dialog.h"
#include<iostream>
using namespace std;
#include <QDebug>
#include<thread>

#include <QApplication>

int add(int a,int b)
{
    qDebug()<<"add";
    qDebug()<<"a+b = "<<a+b;
    _sleep(1000);
    return a+b;
}

class AA
{
public:
    AA(){
        //在构造函数中创建线程
        //如果使用_beginthreadex 线程函数是static
        thread th(&threadFun,this);
        th.detach();
    }
    //执行detach之后线程如何退出
    //设置标志位
    void threadFun(){
        while(!m_isQuit)
        {
            _sleep(100);
            qDebug()<<"do some work";
        }
    }
private:
    bool m_isQuit = false;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    {
        thread th(&add,3,4);//线程函数可以以参数形式传入
        //join函数 阻塞当前线程 直到线程函数退出
//        _sleep(100);
//        qDebug()<<"before join";
//        th.join();
//        qDebug()<<"thread join";

        //detach 将线程对象与线程函数分离,线程不依赖线程对象管理
          qDebug()<<"before detach";
          th.detach();
          qDebug()<<"after detach";
          //注:join和detach两者必选其一,否则线程对象的回收会影响线程的回收,导致程序崩溃
    }
    Dialog w;
    w.show();
    return a.exec();
}

看下面一段代码:

执行结果不等于300,为什么?

  • ++g_value时分为三步:读,自增,写。在多线程情况下,可能存在多个线程读或写同一个值的情况,这就使得结果小于我们预期的值了。

线程并发引发的数据问题:

并发:同一时间间隔内,程序交替执行

解决:线程同步

 线程同步:同一时间,只允许一个线程访问资源

实现线程同步方法:

  • 互斥锁
  • 读写锁
  • 条件变量
  • 原子操作
  • 信号和槽
  • 事件循环

1、互斥锁

lock_guardunique_lock 管理互斥锁,让互斥锁使用更方便、更安全(可以避免死锁,比如我们使用完锁忘记释放了)

lock_guardunique_lock 遵循RAII

  • RAII,资源获取即初始化,是C++很重要的思想。

思考:如果需要在中途释放锁,怎么办?

  1. 使用 unique_lock
  2. 使用 lock_guard + 花括号实现,即锁一部分

锁锁定代码长度称为粒度,锁定的代码长度越长,锁的粒度越大,影响并发的效率。

2、条件变量

#include<condition_variable>
std::condition_variable con_var;

con_var.notify_one();(通知一个)

con_var.notify_all();(通知所有)

con_var.wait();

wait() 函数:

  • 有两个参数:第一个参数:是一个已经上锁的互斥锁(unique_lock),第二个参数:是一个可调用对象,其中包含函数指针,仿函数,bind ,lambda表达式
  • 如果这个函数执行返回值是false ,就会通知无效,可以避免误通知
  • 作用:阻塞当前线程,直到收到通知 notify_one notify_all
  • 当调用wait时,释放互斥锁,阻塞当前线程,将线程放入条件变量等待的容器中
  • 当收到通知时,获取互斥锁,执行后续代码
  • wait()和通知的关系:在使用的时候,一定是wait之后才能收到通知,否则会失效

 运行结果:

先打印出三个"before wait",之后每点击一下按钮,打印一个"after wait"

举例:

现在我们改变一下:

运行结果:

我们第一次按下按钮,quit取非为真,此时打印"after wait",再次按下,此时quit取非为假,此时无反应,第三次按下,此时quit又为真,打印"after wait"......

3、原子操作

#include<atomic>
atomic<int> cnt(0);

  • cnt++; 
  • cnt--;
  • cnt.load();
#include "dialog.h"

#include<iostream>
using namespace std;

#include <QDebug>
#include<thread>
#include <QApplication>

#include<atomic>
atomic<int> cnt(0);

void AutomicFunc()
{
    for(int i=0;i<100;i++)
    {
        _sleep(10);
        //cnt++; //加锁的方式进行++,是原子操作,线程安全
        cnt = cnt + 1; //非原子操作,线程不安全
        _sleep(10);
    }
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    {
        thread th[3];
        for(int i=0;i<3;i++)
        {
            th[i] = thread(&AutomicFunc);
        }
        for(int i=0;i<3;i++)
        {
            th[i].join();
        }
    }
    qDebug()<<"count = "<<cnt.load();//取值
    
    Dialog w;
    w.show();
    return a.exec();
}

如有问题,欢迎交流指正! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值