C++:并发与线程(九)

一 std::future的其他成员函数

std::future_status

枚举类型,等待一定时间,查看线程是否执行完
枚举值:time_out ready deferred

#include <iostream>
#include <string>
#include <future>
#include <thread>
#include <mutex>
using namespace  std;

int mythread()
{
    cout<<"mythread start"<<"thread_id:"<<std::this_thread::get_id<<endl;
    //sleep 5s
    std::chrono::milliseconds dura(5000);
    std::this_thread::sleep_for(dura);
    cout<<"mythread over"<<"thread_id:"<<std::this_thread::get_id<<endl;
    return 5;
}
int main()
{
    //一 future的其他成员函数
    cout<<"main"<<"thread_id"<<std::this_thread::get_id<<endl;
    //这里async的创建采用异步模式,即创建完就开始执行线程 std::launch::async
  std::future<int> res = std::async(std::launch::async,mythread);
    cout<<"continue.."<<endl;

//    cout<<res.get()<<endl;   //等待线程操作完成


std::future_status status = res.wait_for(std::chrono::seconds(1)); //等待一秒
if (status == std::future_status::timeout)
{
    //超时,表示线程还没执行完
    cout<<"time out"<<endl;
}
    cout<<"ok"<<endl;
    return 0;
}

主线程等待子线程执行完才结束

G:\C++Code\MultiThread\MultiThread2_10\cmake-build-debug\MultiThread2_10.exe
mainthread_id1
continue..
mythread startthread_id:1
time out
ok
mythread overthread_id:1

Process finished with exit code 0

等待时间改为6s,再获取子线程的状态

#include <iostream>
#include <string>
#include <future>
#include <thread>
#include <mutex>
using namespace  std;

int mythread()
{
    cout<<"mythread start"<<"thread_id:"<<std::this_thread::get_id<<endl;
    //sleep 5s
    std::chrono::milliseconds dura(5000);
    std::this_thread::sleep_for(dura);
    cout<<"mythread over"<<"thread_id:"<<std::this_thread::get_id<<endl;
    return 5;
}
int main()
{
    //一 future的其他成员函数
    cout<<"main"<<"thread_id"<<std::this_thread::get_id<<endl;
    std::future<int> res = std::async(std::launch::async,mythread);
    cout<<"continue.."<<endl;

//    cout<<res.get()<<endl;   //等待线程操作完成


std::future_status status = res.wait_for(std::chrono::seconds(6)); //等待一秒
if (status == std::future_status::timeout)
{
    //超时,表示线程还没执行完
    cout<<"time out"<<endl;
}
else if(status == std::future_status::ready)
{
    //超时,表示线程还没执行完
    cout<<"thread success over"<<endl;
    cout<<res.get()<<endl;
}
    cout<<"ok"<<endl;
    return 0;
}

6s过后,子线程已经执行完成了,status 为ready

G:\C++Code\MultiThread\MultiThread2_10\cmake-build-debug\MultiThread2_10.exe
mainthread_id1
continue..
mythread startthread_id:1
mythread overthread_id:1
thread success over
5
ok

二 std::shared_future

类模板 与std::future不同的是,future对象使用get()获取到值并赋值给其他变量时,使用的是移动语义,数据被转移,赋值完成后,future对象内数据为空;而shared_future使用get()给其他变量赋值时,使用复制的方式,其内部的数据不会被转移。

  cout<<"main"<<"thread_id"<<std::this_thread::get_id<<endl;
    std::future<int> res = std::async(std::launch::async,mythread);
    bool ifcanget = res.valid();  //判断res中是否有值
    cout<<" res ifcanget = "<<ifcanget<<endl;
    //将res的值移动到result中   res 空了 移动语义
    std::shared_future<int>result (res.share());
    ifcanget = res.valid();
    cout<<" res ifcanget = "<<ifcanget<<endl;
    auto myresult = result.get();
    myresult = result.get();
    myresult = result.get();
    myresult = result.get();
    cout<<"result if can get = "<<result.valid()<<endl;
    cout<<"continue.."<<endl;


    cout<<"ok"<<endl;
    return 0;
G:\C++Code\MultiThread\MultiThread2_10\cmake-build-debug\MultiThread2_10.exe
mainthread_id1
 res ifcanget = 1
mythread startthread_id:1
 res ifcanget = 0
mythread overthread_id:1
result if can get = 1
continue..
ok

Process finished with exit code 0


三 原子操作 std::atomic

3.1 原子操作概念引出范例

  • 互斥量:多线程编程中,保护共享数据:锁,操作共享数据,开锁
  • 两个线程,对一个变量进行操作,一个线程读,一个线程写
  • 读线程,读取这个变量的数据
  • 写线程,改变这个变量的值:一个赋值操作,可以分解成多个操作,所以如果执行多个操作中的其中一个步骤时,被读线程打断,则会读到不可预料的值。
int mycount = 0;
void writethread()
{
    for (int i = 0; i < 1000; ++i)
    {
    mycount ++;
    }
}
 thread mytobj1(writethread);
    thread mytobj2(writethread);

    mytobj1.join();
    mytobj2.join();
    cout<<"two thread over,mycount = "<<mycount<<endl;
    cout<<"ok"<<endl;
    return 0;

结果打印:预期结果不是2000000

G:\C++Code\MultiThread\MultiThread2_10\cmake-build-debug\MultiThread2_10.exe
two thread over,mycount = 1380024
ok

Process finished with exit code 0

使用互斥锁解决该问题

std::mutex my_mutex;
void writethread()
{
    for (int i = 0; i < 1000; ++i)
    {
        my_mutex.lock();
    mycount ++;
        my_mutex.unlock();
    }
}

2000000次加锁和解锁
结果打印

G:\C++Code\MultiThread\MultiThread2_10\cmake-build-debug\MultiThread2_10.exe
two thread over,mycount = 2000000
ok

Process finished with exit code 0

原子操作

  1. 在多线程中不会被打断的程序执行片段,其效率比加锁和解锁更胜一筹。
  2. 互斥量的加锁一般针对一行或多行代码,原子操作一般针对一个变量,而不是一段代码段。
  3. 原子操作:可以理解为不可分割的操作。
  4. std::atomic代表原子操作,是个类模板,它是用来封装某个类型的值
  5. 将上述例子中的mycount封装成原子类型数据
//int mycount = 0;

std::atomic<int> mycount ;

3.2 基本的std::atomic用法范例

atomic对象的初始化:其初始化方式有多种,例如

std::atomic<int> mycount(0);

原子数据不需要互斥锁保护

void writethread()
{
    for (int i = 0; i < 1000000; ++i)
    {

    mycount ++;  //mycount为atomic对象,其操作不会被打断

    }
}
   thread mytobj1(writethread);
    thread mytobj2(writethread);

    mytobj1.join();
    mytobj2.join();
    cout<<"two thread over,mycount = "<<mycount<<endl;
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Michael.Scofield

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值