与 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() 函数就声明在此头文件中。

#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;
}  


std::thread 构造

(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 << std::endl;  }
}  void thr_function2(int n)
{  std::cout << "thread 1 print " << n << std::endl;
}  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 htread 2 completed.\n";  return 0;
}  


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

三、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;
}

1、成员类型和成员函数。
2、std::thread 构造函数。
3、异步。
4、多线程传递参数。
5、join、detach。
6、获取CPU核心个数。
7、CPP原子变量与线程安全。
8、lambda与多线程。
9、时间等待相关问题。
10、线程功能拓展。
11、多线程可变参数。
12、线程交换。
13、线程移动。

1、成员类型和成员函数。

2、std::thread 构造函数。


(1).默认构造函数,创建一个空的 thread 执行对象。
(2).初始化构造函数,创建一个 thread 对象,该 thread 对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。
(3).拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。
(4).move 构造函数,move 构造函数,调用成功之后 x 不代表任何 thread 执行对象。
注意:可被 joinable 的 thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached。

#include<thread>
#include<chrono>
using namespace std;
void fun1(int n)  //初始化构造函数
{  cout << "Thread " << n << " executing\n";  n += 10;  this_thread::sleep_for(chrono::milliseconds(10));
}
void fun2(int & n) //拷贝构造函数
{  cout << "Thread " << n << " executing\n";  n += 20;  this_thread::sleep_for(chrono::milliseconds(10));
}
int main()
{  int n = 0;  thread t1;               //t1不是一个thread  thread t2(fun1, n + 1);  //按照值传递  t2.join();  cout << "n=" << n << '\n';  n = 10;  thread t3(fun2, ref(n)); //引用  thread t4(move(t3));     //t4执行t3,t3不是thread  t4.join();  cout << "n=" << n << '\n';  return 0;
}
运行结果:
Thread 1 executing
n=0
Thread 10 executing
n=30

3、异步

#include<thread>
using namespace std;
void show()
{  cout << "hello cplusplus!" << endl;
}
int main()
{  //栈上  thread t1(show);   //根据函数初始化执行  thread t2(show);  thread t3(show);  //线程数组  thread th[3]{thread(show), thread(show), thread(show)};   //堆上  thread *pt1(new thread(show));  thread *pt2(new thread(show));  thread *pt3(new thread(show));  //线程指针数组  thread *pth(new thread[3]{thread(show), thread(show), thread(show)});  return 0;
}

4、多线程传递参数

#include<thread>
using namespace std;
void show(const char *str, const int id)
{  cout << "线程 " << id + 1 << " :" << str << endl;
}
int main()
{  thread t1(show, "hello cplusplus!", 0);  thread t2(show, "你好,C++!", 1);  thread t3(show, "hello!", 2);  return 0;
}
运行结果:
线程 1线程 2 :你好,C++!线程 3 :hello!
:hello cplusplus!

5、join、detach

#include<thread>
#include<array>
using namespace std;
void show()
{  cout << "hello cplusplus!" << endl;
}
int main()
{  array<thread, 3>  threads = { thread(show), thread(show), thread(show) };  for (int i = 0; i < 3; i++)  {  cout << threads[i].joinable() << endl;//判断线程是否可以join  threads[i].join();//主线程等待当前线程执行完成再退出  }  return 0;
}
运行结果:
hello cplusplus!
hello cplusplus!
1
hello cplusplus!
1
1

总结:
join 是让当前主线程等待所有的子线程执行完,才能退出。
detach例子如下:

#include<thread>
using namespace std;
void show()
{  cout << "hello cplusplus!" << endl;
}
int main()
{  thread th(show);  //th.join();   th.detach();//脱离主线程的绑定,主线程挂了,子线程不报错,子线程执行完自动退出。  //detach以后,子线程会成为孤儿线程,线程之间将无法通信。  cout << th.joinable() << endl;  return 0;
}
运行结果:
hello cplusplus! 

结论:
线程 detach 脱离主线程的绑定,主线程挂了,子线程不报错,子线程执行完自动退出。
线程 detach以后,子线程会成为孤儿线程,线程之间将无法通信。

6、获取CPU核心个数。

例如:

#include<thread>
using namespace std;
int main()
{  auto n = thread::hardware_concurrency();//获取cpu核心个数  cout << n << endl;  return 0;
}
运行结果:
8

结论:
通过 thread::hardware_concurrency() 获取 CPU 核心的个数。

7、CPP原子变量与线程安全

问题例如:

**#include<thread>
using namespace std;
const int N = 100000000;
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;
}
运行结果:
num=143653419,用时 730 ms

从上述代码执行的结果,发现结果并不是我们预计的200000000,这是由于线程之间发生冲突,从而导致结果不正确。
为了解决此问题,有以下方法:
(1)互斥量。
例如:

#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;
}
运行结果:
num=200000000,用时 128323 ms

不难发现,通过互斥量后运算结果正确,但是计算速度很慢,原因主要是互斥量加解锁需要时间。
互斥量详细内容 请参考下篇文章C++11 并发之std::mutex。
(2)原子变量。
例如:

#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;
}
运行结果:
num=200000000,用时 29732 ms

不难发现,通过原子变量后运算结果正确,计算速度一般。
原子变量详细内容 请参考C++11 并发之std::atomic。
(3)加入 join 。
例如:

#include<thread>
using namespace std;
const int N = 100000000;
int num = 0;
void run()
{  for (int i = 0; i < N; i++)  {  num++;  }
}
int main()
{  clock_t start = clock();  thread t1(run);  t1.join();  thread t2(run);  t2.join();  clock_t end = clock();  cout << "num=" << num << ",用时 " << end - start << " ms" << endl;  return 0;
}
运行结果:
num=200000000,用时 626 ms

不难发现,通过原子变量后运算结果正确,计算速度也很理想。

8、lambda与多线程。
例如:

#include<thread>
using namespace std;
int main()
{  auto fun = [](const char *str) {cout << str << endl; };  thread t1(fun, "hello world!");  thread t2(fun, "hello beijing!");  return 0;
}
运行结果:
hello world!
hello beijing

9、时间等待相关问题。
例如:

#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、线程功能拓展。

例如:

#include<thread>
using namespace std;
class MyThread :public thread   //继承thread
{
public:  //子类MyThread()继承thread()的构造函数  MyThread() : thread()  {  }  //MyThread()初始化构造函数  template<typename T, typename...Args>  MyThread(T&&func, Args&&...args) : thread(forward<T>(func), forward<Args>(args)...)  {  }  void showcmd(const char *str)  //运行system  {  system(str);  }
};
int main()
{  MyThread th1([]()  {  cout << "hello" << endl;  });  th1.showcmd("calc"); //运行calc  //lambda  MyThread th2([](const char * str)  {  cout << "hello" << str << endl;  }, " this is MyThread");  th2.showcmd("notepad");//运行notepad  return 0;
}
运行结果:
hello
//运行calc
hello this is MyThread
//运行notepad

11、多线程可变参数

例如:

#include<thread>
#include<cstdarg>
using namespace std;
int show(const char *fun, ...)
{  va_list ap;//指针  va_start(ap, fun);//开始  vprintf(fun, ap);//调用  va_end(ap);  return 0;
}
int main()
{  thread t1(show, "%s    %d    %c    %f", "hello world!", 100, 'A', 3.14159);  return 0;
}
运行结果:
hello world!    100    A    3.14159

12、线程交换。
例如:

#include<thread>
using namespace std;
int main()
{  thread t1([]()  {  cout << "thread1" << endl;  });  thread t2([]()  {  cout << "thread2" << endl;  });  cout << "thread1' id is " << t1.get_id() << endl;  cout << "thread2' id is " << t2.get_id() << endl;  cout << "swap after:" << endl;  swap(t1, t2);//线程交换  cout << "thread1' id is " << t1.get_id() << endl;  cout << "thread2' id is " << t2.get_id() << endl;  return 0;
}
运行结果:
thread1
thread2
thread1' id is 4836
thread2' id is 4724
swap after:
thread1' id is 4724
thread2' id is 4836

两个线程通过 swap 进行交换。

13、线程移动

例如:

#include<thread>
using namespace std;
int main()
{  thread t1([]()  {  cout << "thread1" << endl;  });  cout << "thread1' id is " << t1.get_id() << endl;  thread t2 = move(t1);;  cout << "thread2' id is " << t2.get_id() << endl;
    return 0;
}
运行结果:
thread1
thread1' id is 5620
thread2' id is 5620

从上述代码中,线程t2可以通过 move 移动 t1 来获取 t1 的全部属性,而 t1 却销毁了。

C++多线程(一)thread类相关推荐

  1. C++多线程:thread类创建线程的多种方式

    文章目录 描述 函数成员简介 总结 描述 头文件 <thread> 声明方式:std::thread <obj> 简介 线程在构造关联的线程对象时立即开始执行,从提供给作为构造 ...

  2. java多线程(一)-Thread类和Runnable接口

    public class Thread extends Object implements Runnable Thread通过实现Runnable实现多态关系. Java中实现多线程,最基本2种方式: ...

  3. PYTHON——多线程:Thread类与线程函数

    Thread类与线程函数 可以使用Thread对象的join方法等待线程执行完毕:主线程(main()函数)中调用Thread对象的join方法,并且Thread对象的线程函数没有执行完毕,主线程会处 ...

  4. python多线程:Thread类的用法

    我们要创建Thread对象,然后让他们运行,每个Thread对象代表一个线程,在每个线程中我们可以让程序处理不同的任务,这就是多线程编程. 创建Thread对象有两种方法: 1.直接创建Thread, ...

  5. Java多线程-继承Thread类,示例

    继承Thread类,调用start方法启动线程. 示例, public class ThreadTest extends Thread {public ThreadTest(String name){ ...

  6. Java继承Thread类创建多线程

    Java继承Thread类创建多线程 单线程示例 示例,Example01.java public class Example01{public static void main(String[] a ...

  7. java同步锁售票_Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)...

    学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是 ...

  8. Java多线程(二):Thread类

    Thread类的实例方法 start() start方法内部会调用方法start方法启动一个线程,该线程返回start方法,同时Java虚拟机调用native start0启动另一个线程调用run方法 ...

  9. 继承Thread类使用多线程

    java实现多线程有两种方式,一种是继承Thread类,另外一种就是实现Runnable接口. 两种实现方法的优缺点: 使用Thread类实现多线程局限性就是不支持多继承,因为java是不支持类多继承 ...

  10. 线程的创建与启动——Thread 类有两个常用的构造方法:Thread()与 Thread(Runnable)||多线程运行结果是随机的

    线程的创建与启动 在 Java 中,创建一个线程就是创建一个 Thread 类(子类)的对象(实例). Thread 类有两个常用的构造方法:Thread()与 Thread(Runnable).对应 ...

最新文章

  1. django 设置媒体url_Django设置网站地图sitemap
  2. 海思3536:PC客户端编译过程报错及解决方法
  3. 编程中python怎么读-对Python新手编程过程中如何规避一些常见问题的建议
  4. http://127.0.0.1:8000/accounts/login/总是重定向到http://127.0.0.1:8000/accounts/profile/并且报告404
  5. Linux查看设备 eth,lspci grep Eth,查看Linux下的各种硬件设备是否识别或存在之用
  6. alter id order by_声卡id查找表
  7. Spring详细导包截图以及IOC和DI思想
  8. python如何读取csv文件某几行某几列_关于python:读取.csv文件时,我似乎无法指定列dtypes...
  9. Ubuntu中apt与apt-get命令的区别
  10. 欧科云链OKLink:以太坊网络难度达到5.74P的历史新高
  11. 灵光一闪-(面对对象实践)
  12. 北风设计模式课程---代理模式
  13. 山大泰克条屏写串口的核心代码(海宏原创,转载请注明)
  14. @order 注解用法
  15. 婚礼上可用的 八荣八耻(大全)
  16. 4.1 心跳机制和垃圾回收机制
  17. 【洛谷2791】 幼儿园篮球题 第二类斯特林数+NTT
  18. icloud 照片导出_如何将iCloud照片用作Apple TV的屏幕保护程序
  19. java jni udt找不到so_移植UDT到Android平台
  20. 使用DEM和矢量数据绘制地图

热门文章

  1. php mysql摄影网_图片分享网站
  2. python crypt模块_Python的加密模块md5、sha、crypt使用实例
  3. Linux 基本命令(七)
  4. 计算机网络面试常考题目汇总
  5. 曾经流行的计算机病毒及危害,主流计算机病毒有什么危害
  6. MySQL数据库的条件查询
  7. html文字左右边距怎么设置,html内容左右边距怎么设置
  8. 网络营销策划:揭秘企业营销策划方案三大法则
  9. JavaScript 浅拷贝与深拷贝概念及应用 Jquery的浅拷贝和深拷贝
  10. python opencv 文字识别_文本识别 使用 Tesseract 进行 OpenCV OCR 和 文本识别