线程的创建和基本使用

文章目录

 

1. 什么是线程? 为什么要用多线程?

线程,是操作系统能够运行和计算和调度的最小单位。一个进程至少要包含一个线程,线程要包含在进程中,是进程实际运作单位。一个进程中可以多有个线程,每个线程并发执行。每个线程有独立的栈空间,线程之间共享静态存储区和堆空间。

那么什么时候要用多线程呢? 当我们要使用并发的时候,就可以使用多线程。比如,我们要想要解码音视频的同时去播放音频和视频;打印机打印PDF并且界面显示当前进度和提示信息等等。

 

2. 线程的创建和使用

 

(1) 使用操作系统API创建

无论是Windows还是Linux,都提供了创建线程的API提供给我们去创建线程。Windows中使用API CreateThread 创建一个线程。它的具体表现形式如下:

  • lpThreadAttributes , 是线程的安全属性,一般设为 nullptr
  • dwStackSize , 表示线程栈空间的大小,单位为字节。一般设置为0,表示默认大小。
  • lpStartAddress , 表示新线程所执行的函数指针,类型为 LPTHREAD_START_ROUTINE 。其定义如下:

    即,一个参数 LPVOID 类型,返回值为 DWORD 类型的函数指针。这里需要指出的是,函数需要使用 WINAPI 修饰,也就是要使用 __stdcall 来修饰函数。

  • lpParameter ,传给线程的参数,LPVOID 类型本质上是 void *
  • dwCreationFlags ,一般设置为0,表示线程创建后立即执行。如果设置为 CREATE_SUSPENDED ,表示使用 ResumeThread 时,线程才开始执行。
  • lpThreadId ,输出参数,返回线程ID。
  • 返回值: 返回线程句柄,如果失败返回空(nullptr)。

下面是一个简单的示例:

函数执行结果如下:
Create Thread Success! Thread ID is 162840
Main Thread ID is 9652
This is Run in Thread ID:16284, Number is :0
This is Run in Thread ID:16284, Number is :1
This is Run in Thread ID:16284, Number is :2
This is Run in Thread ID:16284, Number is :3
This is Run in Thread ID:16284, Number is :4

当然也有可能是创建的线程中先打印,后者同时交替着打印。
函数 createWindowsThread 中使用了Windows的创建线程API CreateThread ,线程中执行函数 threadProc ,while 循环中执行5次后线程退出。

  • GetCurrentThreadId 表示获取当前所在线程的 线程ID
  • WaitForSingleObject 表示等待线程结束。这里第一个参数为线程的句柄,第二个参数用于表示等待的毫秒数,如果设置为 INFINITE ,表示无限等待下去。
 

(2) 使用C++11创建

不同操作系统的创建线程的函数是不同的,比如windows中使用 CreateThread ,而Linux中使用 pthread_create 创建。对于跨平台的开发,我们可以使用Qt等第三方开源库完成跨平台的线程创建,也可以使用C++11中提供的方法创建多线程。当前,使用的编译器要支持C++11。

可以使用C++11提供的 std::thread 实现线程的创建。
我们改写一下上面的例子,代码如下:

程序运行结果如下:
This is Run in Thread ID:10568, Number is :0
This is Run in Thread ID:10568, Number is :1
This is Run in Thread ID:10568, Number is :2
This is Run in Thread ID:10568, Number is :3
This is Run in Thread ID:10568, Number is :4

这里线程中执行的函数可以不指定为 __stdcall 修饰。创建 std::thread 对象,构造函数中传入线程中执行的函数指针和参数,如果没有参数可以不指定。就可以完成线程的创建。

  • detach 表示线程与线程对象分离,线程资源的回收不受线程对象的控制。

如果想等待线程,可使用 join 函数,我们把代码修改如下:

执行结果如下:
This is Run in Thread ID:10568, Number is :0
This is Run in Thread ID:10568, Number is :1
This is Run in Thread ID:10568, Number is :2
This is Run in Thread ID:10568, Number is :3
This is Run in Thread ID:10568, Number is :4
Created Thread Finished!

这里因为 std::thread 实现了移动构造,所以当函数中的线程对象被消除的时候,线程的相关信息转移给了新创建的线程函数。

  • join 函数,表示阻塞等待线程的结束,如果线程结束则继续往下执行。joinable 方法可以判断能否被 join ,在 join 前需要调用该方法。
 

(3) c++11线程ID的获取

前面说了Windows的API获取线程ID的方法,那么如何使用C++11来获取线程ID呢?

  • 可以使用 std::this_thread 类的 get_id 获取当前线程的ID,这是一个静态方法。
  • 也可以使用 std::thread 对象的 get_id 获取线程ID。
    get_id 函数返回的为一个 std::thread::id 的对象,无法直接通过该对象获取线程ID的整数值,但是该对象重载了 << 方法,如果想获取整数值需要借助 std::ostringstream 实现。添加头文件 #include <sstream>

具体实现代码如下:


代码下载
https://github.com/douzhongqiang/threadCode/tree/master/CreateThread

You May Also Like

About the Author: admin

喜欢编程、爱游戏,更爱生活。

发表评论

电子邮件地址不会被公开。