背景

面对一个任务并行的多线程问题,我们首先要将总任务分为多个子任务,一个子任务就可以放入一个线程中执行,这时我们需要编写多个线程,每个线程负责独立的任务;

而面对一个数据并行的多线程问题,我们只有一个任务,是将数据分为多个独立的子数据,每个数据都执行同样的任务,这时我们只需要编写一个线程,通过管理线程的输入来完成多个子数据的并行任务。

所以我们把线程想象成任务即可,这个任务要完成多少工作无关紧要,只要多个任务是独立的,或者同一个任务有多个独立的输入。

线程函数

CreateThread

在Windows系统中,我们可以使用CreateThread函数:

HANDLE WINAPI CreateThread(_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,_In_ SIZE_T dwStackSize,_In_ LPTHREAD_START_ROUTINE lpStartAddress,_In_opt_ __drv_aliasesMem LPVOID lpParameter,_In_ DWORD dwCreationFlags,_Out_opt_ LPDWORD lpThreadId
);

函数说明:

  • 第一个参数表示线程内核对象的安全属性,一般传入NULL表示使用默认设置。
  • 第二个参数表示线程栈空间大小。传入0表示使用默认大小(1MB)。
  • 第三个参数表示新线程所执行的线程函数地址,多个线程可以使用同一个函数地址。
  • 第四个参数是传给线程函数的参数。
  • 第五个参数指定额外的标志来控制线程的创建,为0表示线程创建之后立即就可以进行调度,如果为CREATE_SUSPENDED则表示线程创建后暂停运行,这样它就无法调度,直到调用ResumeThread()。
  • 第六个参数将返回线程的ID号,传入NULL表示不需要返回该线程ID号。

函数返回值:成功返回新线程的句柄,失败返回NULL。

CreateThread对应的关闭线程函数为为 ExitThread

_beginthread

实际上,CreateThread函数并不被推荐使用, _beginthread要比CreateThread安全,它是对CreateThread函数的封装,并针对CreateThread在调用CRT库时的内存泄漏问题进行了处理,所以比CreateThread更加安全。_beginthread定义如下:

uintptr_t _beginthread(void( *start_address )( void * ),unsigned stack_size,void *arglist
);

参数说明:

  • start_address:新线程的起始地址 ,指向新线程调用的函数的起始地址,为函数名。函数的声明方式很简单:

    void 函数名(LPVOID lpParam)
    
  • stack_size:新线程的堆栈大小,一般为0

  • arglist:传递给线程的参数列表,无参数时为NULL

_beginthread对应的关闭线程函数为为_endthread

_beginthreadex

_beginthread函数非常简单,易上手,但参数太少也有缺点,和CreateThread比起来似乎可控制性不强。我们还可以使用另一个函数_beginthreadex

unsigned long _beginthreadex(void *security,unsigned stack_size,unsigned(_stdcall *start_address)(void *),void *argilist,unsigned initflag,unsigned *threaddr
);

参数说明:

  • security:安全属性, 为NULL时表示默认安全性
  • stack_size:线程的堆栈大小, 一般默认为0
  • start_address:所要启动的线程函数
  • argilist:线程函数的参数, 是一个void*类型, 传递多个参数时用结构体
  • flag:新线程的初始状态,0表示立即执行,CREATE_SUSPEND表示创建之后挂起
  • threaddr:线程ID地址

返回值:成功返回新线程句柄, 失败返回0

可以看到,_beginthreadex就像_beginthread的扩展体,增加了三个参数,是可控制性更好一些。两个函数的不同点如下:

  • 多3个参数:intiflag,security和threadaddr。

  • 线程函数的声明方式不同。_beginthreadex()的线程函数必须使用_stdcall修饰符,且必须返回一个unsigned int型的退出码。

    unsigned __stdcall 函数名(void* param)
    
  • _beginthreadex()在创建线程失败时返回0,而_beginthread()在创建线程失败时返回-1。这一点是在检查返回结果时必须注意的。

  • 如果是调用_beginthread创建线程,则相应地调用_endthread结束线程时,系统会自动关闭线程句柄;而调用_beginthreadex创建线程,相应地调用_endthreadx结束线程时,系统不能自动关闭线程句柄。因此调用_beginthreadex创建线程还需程序员自己关闭线程句柄,以清除线程的地址空间

WaitForSingleObject

函数功能:等待函数 – 使线程进入等待状态,直到指定的内核对象被触发。

函数原型:

DWORD WINAPI WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds
);

参数说明:

  • 第一个参数为要等待的内核对象。
  • 第二个参数为最长等待的时间,以毫秒为单位,如传入5000就表示5秒,传入0就立即返回,传入INFINITE表示无限等待。

因为线程的句柄在线程运行时是未触发的,线程结束运行,句柄处于触发状态。所以可以用WaitForSingleObject()来等待一个线程结束运行。

函数返回值:

在指定的时间内对象被触发,函数返回WAIT_OBJECT_0。超过最长等待时间对象仍未被触发返回WAIT_TIMEOUT。传入参数有错误将返回WAIT_FAILED

实例

//子线程报数
#include <stdio.h>
#include <process.h>
#include <windows.h>
int g_nCount;
//子线程函数
unsigned int __stdcall ThreadFun(PVOID pM)
{g_nCount++;printf("线程ID号为%4d的子线程报数%d\n", GetCurrentThreadId(), g_nCount);return 0;
}
//主函数,所谓主函数其实就是主线程执行的函数。
int main()
{printf("     子线程报数 \n");printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");const int THREAD_NUM = 10;HANDLE handle[THREAD_NUM];g_nCount = 0;for (int i = 0; i < THREAD_NUM; i++)handle[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);return 0;
}

多线程一之Thread创建、运行、结束相关推荐

  1. JAVA重点类 多线程Thread 创建 生命周期 同步

    一.多线程基本概念 1.程序(program)是为完成特定任务.用某种语言编写的一组指令的集合.即指一段静态的代码,静态对象. 说明:软件安装好了,但是还没跑起来,此时就是静态代码.比如qq,游戏,还 ...

  2. 继承Thread 创建多线程的简单实现

    /*** 继承Thread 创建多线程的简单实现* @author silence*/ public class MyThread extends Thread {@Overridepublic vo ...

  3. java结束全部操作代码_Java创建与结束线程代码示例

    这篇文章主要介绍了Java创建与结束线程代码示例,小编觉得挺不错的,这里分享给大家,供需要的朋友参考. 本文讲述了在Java中如何创建和结束线程的最基本方法,只针对于Java初学者.一些高级知识如线程 ...

  4. java创建线程代码_Java创建与结束线程代码示例

    本文讲述了在Java中如何创建和结束线程的最基本方法,只针对于Java初学者.一些高级知识如线程同步.调度.线程池等内容将会在后续章节中逐步深入. 创建线程 创建普通线程有两种方式,继承Thread类 ...

  5. [python学习] 专题八.多线程编程之thread和threading

    就个人而言,学了这么多年的课程又写了这么多年的程序,虽然没有涉及到企业级的项目,但还是体会到了有几个知识点是非常重要的,包括:面向对象的思想.如何架构一个项目.设计模式来具体解决问题.应用机器学习和深 ...

  6. VC多线程编程之线程创建与示例

    一.问题的提出 编写一个耗时的单线程程序: 新建一个基于对话框的应用程序SingleThread,在主对话框IDD_SINGLETHREAD_DIALOG添加一个按钮,ID为IDC_SLEEP_SIX ...

  7. PySide2多线程问题示例:创建新线程、子线程发射信号到主界面

    PySide2多线程问题示例:创建新线程.子线程发射信号到主界面 本文是在pyside学习过程中的记录,从无子线程.子线程在主程序中直接操作Qt界面.子线程发射信号操作主界面三个步骤出发,记录对多线程 ...

  8. C++并发编程之Thread创建和退出

    1.线程的基本概念 线程的基本概念,我们看下定义: 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多 ...

  9. C++多线程:std::thread

    最近这段时间在学习C++多线程相关的知识,打算将学习的内容记录下来,加深理解和记忆. C++11 新标准中引入了五个头文件来支持多线程编程,他们分别是<atomic> ,<threa ...

最新文章

  1. 【机器学习】最容易实现的基于OpenCV的人脸检测代码、检测器及检测效果
  2. 云炬创业政策学习笔记20210115
  3. Grafana Worldmap外网用户request地图监控
  4. Linux 进程间通信:管道、共享内存、消息队列、信号量
  5. java连接mysql封装代码_JDBC连接数据库方法的封装,以及查询数据方法的封装
  6. PDFDOC365工具箱
  7. 动态图片怎么制作 html,怎么制作动态图片
  8. 超启发式算法(hyper heuristic)
  9. 程序猿生存指南-63 贪心姑娘
  10. add p4 多个文件_P4_tutorials
  11. 小清新版js扫雷(使用原生js)
  12. 机器学习之决策树算法前期(创建、分类及展示)
  13. 台式计算机硬盘主要有哪两种接口,台式机硬盘和笔记本硬盘都有哪些区别?
  14. 【珍藏版】 2012Java开发工程师必备精品资料(115个)
  15. 计算机类sci中接受综述么,SCI期刊接受的5大类型文章
  16. 分享!史上最全的STM32库....
  17. 实现库房批次管理,先进先出原则(一次难忘的找bug经历)
  18. windows的bat批处理启动软件,程序员必备技能
  19. 应用程序中的服务器错误 怎么解决办法,iwms出现“/”应用程序中的服务器错误。解决办法...
  20. 【Flutter 实战】简约而不简单的计算器

热门文章

  1. 从高考到程序员,就这样慢慢的生活挺好
  2. 解决vs打开历史项目提示不兼容或打开失败
  3. Android实用应用,Android 4.0系统+实用应用_手机_手机Android频道-中关村在线
  4. HBase系列从入门到精通(二)
  5. csgo搭建显示段位的服务器,csgo怎么让别人看不见自己的段位 | 手游网游页游攻略大全...
  6. lab2 基于VMware虚拟化的跨网段访问(使用海蜘蛛)
  7. C#实现textBox滚动条自动滚到最底端
  8. 计算机的外设配置,CSGO萌新必看电脑配置及外设选择建议心得分享
  9. 【转】宽带连接错误的处理办法691、623、678、645、720、721、718、734、769、619、676、815
  10. 保持计算机软件和硬件在预算之内的程序员指南