c++11并发

转载

一. 多线程并发

1. 与 C++11 多线程相关的头文件
  • 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_variablestd::condition_variable_any
  • <future>:该头文件主要声明了 std::promise, std::package_task 两个 Provider 类,以及 std::futurestd::shared_future 两个 Future 类,另外还有一些与之相关的类型和函数,std::async() 函数就声明在此头文件中。
  • 和有些语言中定义的线程不同,C++11 所定义的线程是和操作系的线程是一一对应的,也就是说我们生成的线程都是直接接受操作系统的调度的,通过操作系统的相关命令(比如 ps -M 命令)是可以看到的,一个进程所能创建的线程数目以及一个操作系统所能创建的总的线程数目等都由运行时操作系统限定。
  • thread 类是一个特殊的类,它不能被拷贝,只能被转移或者互换
  • 线程的转移使用 move 函数,如thread t2 = move(t);
  • thread t2 = move(t); // 改为 t2 = t 将不能编译。
    t2.join();
  • 如果将 t2.join() 改为 t.join() 将会导致整个进程被结束,因为忘记了调用 t2 也就是被转移的线程的 join() 方法,从而导致整个进程被结束,而 t 则因为已经被转移,其 id 已被置空。
  • 线程实例互换使用 swap 函数,如线程实例互换使用 swap 函数
  • 在进行线程实例转移的时候,要注意判断目的实例的 id 是否为空值。
  • std::this_thread::sleep_for(chrono::milliseconds(10)):表示当前线程休眠一段时间(10ms),休眠期间不与其他线程竞争 CPU,根据线程需求,等待若干时间。需要引入头文件#include <chrono>
2. join() 函数与 detach() 函数
  • join()函数是一个等待线程完成函数,主线程需要等待子线程运行结束了才可以结束;
  • detach()函数称为分离线程函数,使用detach()函数会让线程在后台运行,即说明主线程不会等待子线程运行结束才结束。
  • join()函数,主线程就会等待子线程运行结束,然后主线程再运行,直到结束,传统编程就是如此;
  • detach()函数,detach即分离的意思,一旦线程detach,也就是说将子线程交给系统托管,与进程,主线程无关了,这种情况下,就很可能主线程结束,子线程还在运行,所以使用detach()就引发出问题,编程的难度也加大了。
  • 线程detach以后,子线程会成为孤儿线程,线程之间将无法通信。
  • auto n = thread::hardware_concurrency();//获取cpu核心个数
3. mutex 互斥量
  • 引入头文件#include <mutex>
  • 定义两个全局变量 int num(0);mutex m;
  • 在线程中要对num操作前后,分别对m加锁和解锁。
void run() {
	m.lock();
	num++;
	m.unlock();
} 
    • 通过互斥量后运算结果正确,但是计算速度很慢,原因主要是互斥量加解锁需要时间
#include<iostream>  
#include<thread>  
#include<mutex>  
using namespace std;  
const int N = 100000000;  
int num(0);  
mutex m;  
void run()  
{  
    for (int i = 0; i < N; i++)  
    {  
        m.lock();  
        num++;  
        m.unlock();  
    }  
}  
int main()  
{  
    clock_t start = clock();  
    thread t1(run);  
    thread t2(run);  
    t1.join();  
    t2.join();  
    clock_t end = clock();  
    cout << "num=" << num << ",用时 " << end - start << " ms" << endl;  
    return 0;  
}
4. 原子变量
  • 引入头文件#include <atomic>
  • 定义一个全局的原子变量:atomic_int num{0};则不会发生线程冲突,即线程安全
void run() {
	for(int i = 0; i < 8; i++)
		num++;
}
  • 通过原子变量后运算结果正确,计算速度一般。
#include<iostream>  
#include<thread>  
#include<atomic>  
using namespace std;  
const int N = 100000000;  
atomic_int num{ 0 };//不会发生线程冲突,线程安全  
void run()  
{  
    for (int i = 0; i < N; i++)  
    {  
        num++;  
    }  
}  
int main()  
{  
    clock_t start = clock();  
    thread t1(run);  
    thread t2(run);  
    t1.join();  
    t2.join();  
    clock_t end = clock();  
    cout << "num=" << num << ",用时 " << end - start << " ms" << endl;  
    return 0;  
}
5. 使用 join() 函数
  • 定义全局变量int num = 0;
  • mian()函数中对线程t1使用join()函数
int main() {
	...
	thread t1(run);
	t1.join();
	...
	return 0;
}
  • 运算结果正确,计算速度也很理想。
6. 时间等待相关问题
#include<iostream>  
#include<thread>  
#include<chrono>  
using namespace std;  
int main()  
{  
    thread th1([]()  
    {  
        //让线程等待3秒  
        this_thread::sleep_for(chrono::seconds(3));  
        //让cpu执行其他空闲的线程  
        this_thread::yield();  
        //线程id  
        cout << this_thread::get_id() << endl;  
    });  
    return 0;  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值