C++多线程和原子操作--2017-7-20

来源:互联网 发布:cf手游刷图软件 编辑:程序博客网 时间:2024/06/06 04:01

C++ 多线程

多线程和原子操作

这些都是C++11引入的类库,从此以后,C++语言本身有了并发编程的能力,非常酷。一个 thread类,三五行代码,就可以启动一个线程,简单的使用mutex和lock_guard ,就可以完成线程间的资源同步与保护,棒极了。


本篇博客主要介绍C++ 的多线程机制。

多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序。一般情况下,两种类型的多任务处理:基于进程和基于线程。

  • 基于进程的多任务处理是程序的并发执行。

  • 线程的多任务处理是同一程序的片段的并发执行。

多线程程序包含可以同时运行的两个或多个部分。这样的程序中的每个部分称为一个线程,每个线程定义了一个单独的执行路径。

一、与 C++11 多线程相关的头文件地方

C++11 新标准中引入了四个头文件来支持多线程编程,他们分别是<atomic> ,<thread>,<mutex>,<condition_variable>和<future>。
  • <atomic>:该头文主要声明了两个类, std::atomic 和 std::atomic_flag,另外还声明了一套 C 风格的原子类型和与 C 兼容的原子操作的函数。
  • <thread>:该头文件主要声明了 std::thread 类,另外 std::this_thread 命名空间也在该头文件中。
  • <mutex>:该头文件主要声明了与互斥量(mutex)相关的类,包括 std::mutex 系列类,std::lock_guard, std::unique_lock, 以及其他的类型和函数。
  • <condition_variable>:该头文件主要声明了与条件变量相关的类,包括 std::condition_variable 和 std::condition_variable_any。
  • <future>:该头文件主要声明了 std::promise, std::package_task 两个 Provider 类,以及 std::future 和 std::shared_future 两个 Future 类,另外还有一些与之相关的类型和函数,std::async() 函数就声明在此头文件中。
本篇博文研究的是thread头文件中的类:
我们来看第一个利用c++11特性创建线程的例子:
#include <iostream>  
#include <thread>  
using namespace std;

void th_function()
{
std::cout << "hello thread." << std::endl;
}


int main(int argc, char *argv[])
{
std::thread t(th_function);  //声明一个线程类对象
t.join();

return 0;
}


二、现在我们来看看c++ 11中thread头文件中的thread类:



三、std::thread 构造

default (1)
thread() noexcept;
initialization (2)
template <class Fn, class... Args>explicit thread (Fn&& fn, Args&&... args);
copy [deleted] (3)
thread (const thread&) = delete;
move (4)
thread (thread&& x) noexcept;
(1). 默认构造函数,创建一个空的 thread 执行对象。
(2). 初始化构造函数,创建一个 thread对象,该 thread对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。
(3). 拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。
(4). move 构造函数,move 构造函数,调用成功之后 x 不代表任何 thread 执行对象。
注意:可被 joinable 的 thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached.
看一个例子:
   这个例子中创建了两个线程,其中一个线程函数带参数,大家仔细分析上面的thread类的构函数,看如何创建线程。
// thread example  
#include <iostream>       // std::cout  
#include <thread>         // std::thread  


void thr_function1()
{
for (int i = 0; i != 10; ++i)
{
std::cout << "thread 1 print " << i << '\n';
}
}


void thr_function2(int n)
{
std::cout << "thread 2 print " << n << '\n';
}


int main()
{
std::thread t1(thr_function1);     // spawn new thread that calls foo()  
std::thread t2(thr_function2, 111);  // spawn new thread that calls bar(0)  


std::cout << "main, foo and bar now execute concurrently...\n";    //同时


// synchronize threads:  同步
t1.join();                // pauses until first finishes  
t2.join();               // pauses until second finishes  


std::cout << "thread 1 and thread 2 completed.\n";


return 0;
}


也有可能是这样的

大家的输出可能不是这样,有可能是下面这样的,不要紧,因为这个例子中没使用多线程的异步机制,线程之间存在竞争,看稍后文章讲解所以输出可能是下面这样的情况。

参考网址:http://blog.csdn.net/chenxun_2010/article/details/49785611


三、move 赋值操作

move (1)
thread& operator= (thread&& rhs) noexcept;
copy [deleted] (2)
thread& operator= (const thread&) = delete;
  • (1). move 赋值操作,如果当前对象不可 joinable,需要传递一个右值引用(rhs)给 move 赋值操作;如果当前对象可被 joinable,则 terminate() 报错。
  • (2). 拷贝赋值操作被禁用,thread 对象不可被拷贝。
看下面的例子。

// example for thread::operator=  
#include <iostream>       // std::cout  
#include <thread>         // std::thread, std::this_thread::sleep_for  
#include <chrono>         // std::chrono::seconds  


void pause_thread(int n)
{
std::this_thread::sleep_for(std::chrono::seconds(n));//c++11 this_thread 类  
std::cout << "pause of " << n << " seconds ended\n";
}


int main()
{
std::thread threads[5];                         // default-constructed threads  


std::cout << "Spawning 5 threads...\n";
for (int i = 0; i<5; ++i)
threads[i] = std::thread(pause_thread, i + 1);   // move-assign threads 这里调用move复制函数  


std::cout << "Done spawning threads. Now waiting for them to join:\n";
for (int i = 0; i<5; ++i)
threads[i].join();


std::cout << "All threads joined!\n";


return 0;
}