C++11并发编程学习笔记

首先需要注意的是:C++11中的线程需要VS2012以上版本才可以,否则程序不识别头文件#include<thread>,所有的线程工具均在这个头文件中。

一、C++11并发编程:thread简单的认识:

1、创建线程实例时,必须提供该线程将要执行的函数,方法之一就是传递一个函数指针。测试代码如下:

#include<thread>
#include<iostream>
using namespace std;
//using std::cout;
//using std::endl;
//using std::thread;
voidhello()
{
        cout<<"Hello from thread!"<<endl;
}
int main()
{
        threadt1(hello);
        t1.join();//直到t1结束,main才返回,若不加该句,则可能t1未结束main就返回,该句的作用是等待被join的线程结束main才返回
        return 0;
}

运行结果为:

Hello from thread!

2、区分线程:

每个线程都有唯一的ID,使用std:thread类的get_id()便可获得线程对应的唯一的ID。

示例代码如下:

#include<thread>
#include<iostream>
#include<vector>
using namespace std;
voidhello()
{
        cout<<"Hello fromthread:"<<this_thread::get_id()<<endl;
}
intmain()
{
        vector<thread>threads;
        for(inti=0;i<5;i++)
        {
                threads.push_back(thread(hello));
        }
        //C++11包含的一种新的for循环,for循环遍历threads赋值给th
        for(auto& th :threads) //让编译器通过初始值来推算变量类型
        {
        th.join();
    }
        return 0;
}

3、使用Lambda 启动线程。

当线程所要执行的代码非常短小时,没有必要专门为之创建一个函数,可使用Lambda代替。

#include<thread>
#include<iostream>
#include<vector>
using namespace std;
intmain()
{
        vector<thread>threads;
        for(int i = 0; i < 5;++i)
        {
                threads.push_back(std::thread(
            [](){
            cout << "Hellofrom thread " << this_thread::get_id() << endl;
        }));
    }
        //C++11包含的一种新的for循环,for循环遍历threads赋值给th
        for(auto& th :threads)
        {
           th.join();
       }
        return 0;
}

二、C++11并发编程:保护共享资源

1、同步问题:

  使用简单的计数器作为示例,该计数器为结构体,它拥有计数变量以及增加或减少计数函数,例如:

#include<thread>
#include <iostream>
#include <vector>
using namespace std;
structCounter {
    int m_nValue;

Counter(intn = 0) : m_nValue(n){}

voidincrement(){ ++m_nValue; }
};

intmain(){
    Counter counter;
    vector<thread>threads;
    for(int i = 0; i < 5; ++i){
       threads.push_back(thread([&counter](){
            for(int i = 0; i < 999999;++i){
                counter.increment();
            }
        }));
    }

for(auto&th : threads){
        th.join();
    }

cout<< counter.m_nValue << endl;
    return 0;
}

每次运行结果不一样,因为计数器的increment()并非原子操作,而是由三个独立的操作完成的:

(1)读取m_nValue;

(2)将m_nValue的值+1;

(3)将+1后的值返回Value变量。

当单线程运行上述代码,每次运行的结果是一样的,上述三个步骤会按顺序进行。但是在多进程情况下,可能存在如下执行顺序:

  1. 线程a:读取 m_nValue的当前值,得到值为 0。加1。得到1,但还没来得及写回内存
  2. 线程b:读取 m_nValue的当前值,得到值为 0。加1。得到1,但还没来得及写回内存。
  3. 线程a:将 1 写回 m_nValue 内存并返回 1。
  4. 线程b:将 1 写回 m_nValue内存并返回 1。

这种情况源于线程间的interleaving(交叉运行)。

解决交叉运行的方法之一就是互斥量。在同一时刻只有一个线程能够得到该对象上的锁。借助互斥量这种简而有力的性质,我们便可以解决线程同步问题。

为了计数器具有线程的安全性,需要添加std::mutex 成员,并在成员函数中对互斥量进行 lock()和unlock()调用。

struct Counter {
    int m_nValue;
    mutex mtx;
Counter(): m_nValue(0){}

voidincrement(){
        mtx.lock();
        ++m_nValue;
        mtx.unlock();
    }
};

需添加头文件 #include<mutex>//C++11中存放互斥量的头文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Linda Fan

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

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

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

打赏作者

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

抵扣说明:

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

余额充值