多线程编程中,有时我们需要等待某一线程完成了特定的操作后再继续做其他事情,要实现这个目的,可以使用Windows API函数WaitForSingleObject,或者WaitForMultipleObjects。这两个函数都会等待Object被标为有信号(signaled)时才返回。只要是Windows创建的Object都会被赋予一个状态量。如果Object被激活了,或者正在使用,那么该Object就是无信号,也就是不可用;另一方面,如果Object可用了,那么它就恢复有信号了。

一、 等待单个线程返回 WaitForSingleObject

1. 函数原型


DWORD WINAPI WaitForSingleObject(
_In_ HANDLE hHandle,
_In_ DWORD dwMilliseconds
);

2.参数说明

第一个参数 _In_ HANDLE hHandle 是对象的句柄,可以是以下几种:

  • Change notification
  • Console input
  • Event
  • Memory resource notification
  • Mutex
  • Process
  • Semaphore
  • Thread
  • Waitable timer

第二个参数 _In_ DWORD dwMilliseconds 为等待时间,以毫秒为单位。参数dwMilliseconds有两个具有特殊意义的值:0和INFINITE。若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。

3.返回值

  • WAIT_ABANDONED 0x00000080:当hHandle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值。
  • WAIT_OBJECT_0 0x00000000 :指定的对象出有有信号状态
  • WAIT_TIMEOUT 0x00000102:等待超时
  • WAIT_FAILED 0xFFFFFFFF :出现错误,可通过GetLastError得到错误代码

4.实例

1.参数 dwMilliseconds 为0,则该函数立即返回



#include <stdio.h>
#include <windows.h> DWORD WINAPI ThreadFunc(LPVOID); int main()
{
HANDLE hThread; hThread = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL); // 创建线程
printf("我是主线程, pid = %d\n", GetCurrentThreadId()); //输出主线程pid WaitForSingleObject(hThread,0); //不等待,直接返回
return 0;
} DWORD WINAPI ThreadFunc(LPVOID p)
{
Sleep(10000); //睡眠10秒
printf("我是子线程, pid = %d\n", GetCurrentThreadId()); //输出子线程pid return 0;
}

输出如下图,主线程不等待子线程返回,直接返回。

2.参数 dwMilliseconds 为5000,等待5秒后返回。



#include <stdio.h>
#include <windows.h> DWORD WINAPI ThreadFunc(LPVOID); int main()
{
HANDLE hThread; hThread = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL); // 创建线程
printf("我是主线程, pid = %d\n", GetCurrentThreadId()); //输出主线程pid WaitForSingleObject(hThread,5000); //等待5s
return 0;
} DWORD WINAPI ThreadFunc(LPVOID p)
{
printf("我是, pid = %d 的子线程\n", GetCurrentThreadId()); //输出子线程pid
Sleep(10000); //睡眠10秒
printf(" pid = %d 的子线程退出\n", GetCurrentThreadId()); //延时10s后输出 return 0;
}

输出如下图,主线程等待子线程5秒后,子线程还没有执行完,WaitForSingleObject就返回了。

3.参数 dwMilliseconds 为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止


#include <stdio.h>
#include <windows.h> DWORD WINAPI ThreadFunc(LPVOID); int main()
{
HANDLE hThread; hThread = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL); // 创建线程
printf("我是主线程, pid = %d\n", GetCurrentThreadId()); //输出主线程pid WaitForSingleObject(hThread,INFINITE); //一直等待,直到子线程返回
return 0;
} DWORD WINAPI ThreadFunc(LPVOID p)
{
printf("我是, pid = %d 的子线程\n", GetCurrentThreadId()); //输出子线程pid
Sleep(10000); //睡眠10秒
printf(" pid = %d 的子线程退出\n", GetCurrentThreadId()); //延时10s后输出 return 0;
}

输出如下图,主线程一直等待直到子线程还没有执行完毕。

二、 等待多个线程返回 WaitForMulitpleObjects

1. 函数原型

DWORD WINAPI WaitForMultipleObjects(
_In_ DWORD nCount,
_In_ const HANDLE *lpHandles,
_In_ BOOL bWaitAll,
_In_ DWORD dwMilliseconds
);

2.参数说明

  • 第一个参数 DWORD dwCount 为等待的内核对象个数,可以是0到MAXIMUM_WAIT_OBJECTS(64)中的一个值。
  • 第二个参数 CONST HANDLE* phObjects 为一个存放被等待的内核对象句柄的数组
  • 第三个参数 BOOL bWaitAll 是否等到所有内核对象为已通知状态后才返回,如果为TRUE,则只有当等待的所有内核对象为已通知状态时函数才返回,如果为FALSE,则只要一个内核对象为已通知状态,则该函数返回。
  • 第四个参数 DWORD dwMilliseconds 为等待时间,和WaitForSingleObject中的dwMilliseconds参数类似。

3.实例

1.参数 bWaitAll 为 false,只要一个内核对象为已通知状态,则该函数返回。


#include <stdio.h>
#include <windows.h> const unsigned int THREAD_NUM = 10;
DWORD WINAPI ThreadFunc(LPVOID); int main()
{
printf("我是主线程, pid = %d\n", GetCurrentThreadId()); //输出主线程pid
HANDLE hThread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i++)
{
hThread[i] = CreateThread(NULL, 0, ThreadFunc, &i, 0, NULL); // 创建线程
} WaitForMultipleObjects(THREAD_NUM,hThread,false, INFINITE); //只要有一个线程返回就结束
return 0;
} DWORD WINAPI ThreadFunc(LPVOID p)
{
int n = *(int*)p;
Sleep(1000*n); //第 n 个线程睡眠 n 秒
printf("我是, pid = %d 的子线程\n", GetCurrentThreadId()); //输出子线程pid
printf(" pid = %d 的子线程退出\n", GetCurrentThreadId()); return 0;
}

输出如下图,只要有一个线程返回就不再等待其它线程。

2.参数 bWaitAll 为 true,等待所有线程返回。



#include <stdio.h>
#include <windows.h> const unsigned int THREAD_NUM = 10;
DWORD WINAPI ThreadFunc(LPVOID); int main()
{
printf("我是主线程, pid = %d\n", GetCurrentThreadId()); //输出主线程pid
HANDLE hThread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i++)
{
hThread[i] = CreateThread(NULL, 0, ThreadFunc, &i, 0, NULL); // 创建线程
} WaitForMultipleObjects(THREAD_NUM,hThread,true, INFINITE); //一直等待,直到所有子线程全部返回
return 0;
} DWORD WINAPI ThreadFunc(LPVOID p)
{
int n = *(int*)p;
Sleep(1000*n); //第 n 个线程睡眠 n 秒
printf("我是, pid = %d 的子线程\t", GetCurrentThreadId()); //输出子线程pid
printf(" pid = %d 的子线程退出\n\n", GetCurrentThreadId()); //延时10s后输出 return 0;
}

输出如下图,主线程等待所有线程返回。

好了,关于WaitForSingleObject 和 WaitForMultipleObjects这两个函数的介绍就先到这里。 另外上面图中有一行显示了三列,这是正常现象,是由于没有做线程同步造成的,关于线程同步的知识,将在以后的文章中介绍。毕竟多线程的精髓就是线程同步问题。

windows多线程(二) 等待线程返回的更多相关文章

  1. 多线程二:线程池(ThreadPool)

    在上一篇中我们讲解了多线程的一些基本概念,并举了一些例子,在本章中我们将会讲解线程池:ThreadPool. 在开始讲解ThreadPool之前,我们先用下面的例子来回顾一下以前讲过的Thread. ...

  2. java多线程二之线程同步的三种方法

          java多线程的难点是在:处理多个线程同步与并发运行时线程间的通信问题.java在处理线程同步时,常用方法有: 1.synchronized关键字. 2.Lock显示加锁. 3.信号量Se ...

  3. 02等待单个线程返回WaitForSingleObject

    windows 多线程之等待线程返回 ​ 多线程编程中,有时我们需要等待某一线程完成了特定的操作之后再继续做其他事情,要实现这个目的,可以使用 Windows API 函数 WaitForSingle ...

  4. C#多线程编程系列(二)- 线程基础

    目录 C#多线程编程系列(二)- 线程基础 1.1 简介 1.2 创建线程 1.3 暂停线程 1.4 线程等待 1.5 终止线程 1.6 检测线程状态 1.7 线程优先级 1.8 前台线程和后台线程 ...

  5. Java多线程系列--“JUC线程池”03之 线程池原理(二)

    概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...

  6. Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)

    一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会 ...

  7. C语言使用pthread多线程编程(windows系统)二

    我们进行多线程编程,可以有多种选择,可以使用WindowsAPI,如果你在使用GTK,也可以使用GTK实现了的线程库,如果你想让你的程序有更多的移植性你最好是选择POSIX中的Pthread函数库,我 ...

  8. Python中的多线程编程,线程安全与锁(二)

    在我的上篇博文Python中的多线程编程,线程安全与锁(一)中,我们熟悉了多线程编程与线程安全相关重要概念, Threading.Lock实现互斥锁的简单示例,两种死锁(迭代死锁和互相等待死锁)情况及 ...

  9. 03等待多个线程返回WaitForMultipleObject

    二. WaitForMultipleObject 等待单个线程返回 1. 函数原型 DWORD WINAPI WaitForMultipleObjects( _In_ DWORD nCount, _I ...

随机推荐

  1. AGC 015 E - Mr.Aoki Incubator

    E - Mr.Aoki Incubator 链接 题意: 数轴上有N个黑点,每个点都有一个方向向右的正速度v.当两个点在同一个位置上重合时,若其中一个是红色,另一个也变成红色.保证没有相同速度或初始坐 ...

  2. nginx配置转发详解

    nginx各项参数的详细配置 本文主要讲解nginx.conf中server部分配置及多路转发问题: server { listen 9090; server_name 127.0.0.1; #cha ...

  3. 接口测试之基础篇--http协议

     概念:超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议.所有的WWW文件都必须遵守这个标准.设计HTTP最初的目的是为了提供一种 ...

  4. 工作之路---记录LZ如何在两年半的时间内升为PM

    引言 之前的伪PM纠结之路已经渐渐结束,LZ也终于正式爬上了PM的位置,对于LZ来说,这个时间比LZ预计的早来了两年半.说起来,两年半的速度已经算是比较快了,但这之中的努力唯有LZ一人知晓.写这篇文章 ...

  5. 微信小程序—day01

    前言 听说谷歌准备回中国了,玩了一下谷歌刚入驻微信的小程序:“猜画小歌”,又一次见识到了ai的强大魅力.看来python之路,前途还是一片光明的. 因为18年初时的“跳一跳”,带火了微信小程序,一直想 ...

  6. Allegro16.6结构文件dxf文件的输出与导入——凡亿PCB

    在pcb设计中,结构文件的导入是不可或缺的一个步骤,使用allegro16.6软件操作如下. 一.结构文件的输出 1.在allegro16.6将pcb颜色显示设置成只剩需要导出的结构. 2.看到all ...

  7. arpspoof+driftnet+ ARP欺骗简单图片抓取

    arpspoof+driftnet+ ARP欺骗简单图片抓取 driftnet是一款简单而使用的图片捕获工具,可以很方便的在网络数据包中抓取图片.该工具可以实时和离线捕获指定数据包中是图片 环境 受害 ...

  8. Linux学习之常用命令(二)

    1.上次介绍了一些常用的系统命令,这次又总结了一些小命令,故分享一下: 网卡地址查询的命令: ifconfig #不同于Windows系统,它的是ifconfig而不是ipconfig ip -a # ...

  9. LintCode——尾部的零

    尾部的零:设计一个算法,计算出n阶乘中尾部零的个数 样例:11! = 39916800.因此应该返回2 分析:假如你把1 × 2 ×3× 4 ×……×N中每一个因数分解质因数,例如 1 × 2 × 3 ...

  10. 腾讯hr面

    腾讯hr面面经 20181018 寒暄几句 hr自我介绍 hr介绍面试和最后出结果的时间周期 进入主题 自我介绍 考研成绩专业第一 聊考研(考研的经过.考研和保研) 本科成绩 考研成绩超长发挥还是正常 ...