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

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

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

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

#include
#include
using namespace std;
//using std::cout;
//using std::endl;
//using std::thread;
voidhello()
{
        cout<<"Hello from thread!"<

运行结果为:

Hello from thread!

2、区分线程:

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

示例代码如下:

#include
#include
#include
using namespace std;
voidhello()
{
        cout<<"Hello fromthread:"<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
#include
#include
using namespace std;
intmain()
{
        vectorthreads;
        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
#include 
#include 
using namespace std;
structCounter {
    int m_nValue;

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

voidincrement(){ ++m_nValue; }
};

intmain(){
    Counter counter;
    vectorthreads;
    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//C++11中存放互斥量的头文件。

你可能感兴趣的:(C++11并发编程学习笔记)