Windows多线程


创建线程

这里用了createThread函数,但是最好不要用这个,这里为了和书上学习一致,使用这个函数
1、函数原型

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

2、参数意义

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

简单demo

#include "pch.h"
#include <iostream>
#include <Windows.h>

DWORD WINAPI subthread(LPVOID);
int main()
{
	HANDLE hThead;
	DWORD theadId;

	hThead=CreateThread(NULL, 0, subthread, 0, 0, &theadId);
	printf("我是主线程, pid = %d,i have a sub thread pid=%d\n", GetCurrentThreadId(), theadId);  //输出主线程pid
	Sleep(2000);
}
DWORD WINAPI subthread(LPVOID p)
{
	printf("我是子线程, pid = %d\n", GetCurrentThreadId());   //输出子线程pid

	return 0;
}


等待线程返回

我们在学习工作中常常要用到等待线程返回,这里主要有两个函数WaitForSingleObject和WaitForMulitpleObjects

WaitForSingleObject(handle ,milli),参数一看就明白,不多说。

需要注意的一点就是如果想让某个线程一直等待就将第二个参数设置为INFINITE

WaitForMulitpleObjects

函数原型

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

如果WaitForMultipleObjects()第三个参数为true表示等待所有线程返回,false表示有一个返回等待线程就继续运行

printf("我是主线程, pid = %d\n", GetCurrentThreadId());  //输出主线程pid
	HANDLE handles[10] = {0};
	for (int i = 0; i < 10; i++)
	{
		handles[i] = CreateThread(NULL, 0, subthread, &i, 0, &theadId);
	}
	//有一个线程结束就返回
	WaitForMultipleObjects(10, handles, false, INFINITE);
}
DWORD WINAPI subthread(LPVOID p)
{
	int n = *(int*)p;
	Sleep(1000 * n); //第 n 个线程睡眠 n 秒
	printf("我是子线程, pid = %d\n", GetCurrentThreadId());   //输出子线程pid
	return 0;
}

注意上面我们的多个线程并不存在互斥访问资源的现象,但是当我们实际开发时,就会出现互斥访问,需要进行资源同步。

关键段 CriticalSection 声明及相关函数

来看下面的代码


#include "pch.h"
#include <iostream>
#include <Windows.h>

DWORD WINAPI subthread(LPVOID);

UINT count = 0;
int main()
{
	HANDLE hThead;
	DWORD theadId;

	printf("我是主线程, pid = %d\n", GetCurrentThreadId());  //输出主线程pid
	HANDLE handles[10] = {0};
	for (int i = 0; i < 10; i++)
	{
		handles[i] = CreateThread(NULL, 0, subthread, &i, 0, &theadId);
	}
	WaitForMultipleObjects(10, handles, true, INFINITE);

	printf("总共10个线程对count进行操作,结果为:count=%d", count);
}
DWORD WINAPI subthread(LPVOID p)
{
	Sleep(50);
	count++;
	printf("我是子线程, pid = %d\n", GetCurrentThreadId());   //输出子线程pid
	return 0;
}


这里会出现多多个线程同时访问的情况,在我机器上Count=8(每个机器不一样,每次跑都不确定)。现在使用CriticalSection解决这个问题

相关函数
1.函数功能:初始化,定义关键段变量后必须先初始化。
void InitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);

2.函数功能:销毁,用完之后记得销毁。
void DeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);

3.函数功能:进入关键区域,系统保证各线程互斥的进入关键区域。
void EnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);

4.函数功能:离开关关键区域
void LeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);

#include "pch.h"
#include <iostream>
#include <Windows.h>

DWORD WINAPI subthread(LPVOID);

UINT count = 0;

CRITICAL_SECTION cs;
int main()
{
	HANDLE hThead;
	DWORD theadId;

	InitializeCriticalSection(&cs);//初始化关键段

	printf("我是主线程, pid = %d\n", GetCurrentThreadId());  //输出主线程pid
	HANDLE handles[10] = {0};
	for (int i = 0; i < 10; i++)
	{
		handles[i] = CreateThread(NULL, 0, subthread, &i, 0, &theadId);
	}
	WaitForMultipleObjects(10, handles, true, INFINITE);

	printf("总共10个线程对count进行操作,结果为:count=%d", count);

	DeleteCriticalSection(&cs);
}
DWORD WINAPI subthread(LPVOID p)
{
	Sleep(50);
	EnterCriticalSection(&cs);
	count++;
	LeaveCriticalSection(&cs);
	printf("我是子线程, pid = %d\n", GetCurrentThreadId());   //输出子线程pid

	return 0;
}




和信号互斥量大同小异有木有。好啦再见啦,继续加油哟。

附上参考博客
链接: [博客园](https://www.cnblogs.com/ay-a/p/8810766.htmlt).
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值