Windows API线程学习

最近无意发现了c语言里可以调用Windows API来实现多线程,对于我这个小白来可是重大发现!让我看看跟pthread有什么区别:D

一.创建线程

cpp 复制代码
// 创建线程的函数原型
​​​​​​​HANDLE CreateThread(
    LPSECURITY_ATTRIBUTES lpThreadAttributes,  // 安全属性(通常为NULL)
    SIZE_T dwStackSize,                         // 栈大小(0表示默认)
    LPTHREAD_START_ROUTINE lpStartAddress,     // 线程函数地址
    LPVOID lpParameter,                         // 传递给线程的参数
    DWORD dwCreationFlags,                      // 创建标志(0表示立即运行)
    LPDWORD lpThreadId                          // 线程ID(可为NULL)
);

测试:

cpp 复制代码
#include <windows.h>
#include <stdio.h>


DWORD WINAPI myFunction(LPVOID lpParam) { //DWORD是线程的返回类型(Double Word),WINAPI为调用约定,LPVOID为指向任何类型的指针(void*)
    printf("111");
    return 0;
}

int main() {
    // 创建线程
    HANDLE hThread = CreateThread(
        NULL,           //安全属性(默认)
        0,              //栈大小(0=默认1MB)
        myFunction,  	//线程函数地址
        NULL,           // 传递给线程的参数
        0,              // 创建标志(0=立即运行)
        NULL            // 线程ID(不需要可以NULL)
    );
    
    
    // 等待线程结束
    WaitForSingleObject(hThread, INFINITE);//INFINITE表示无限等待,填1000表示最多等1秒
    
    // 关闭句柄
    CloseHandle(hThread);
    
    return 0;
}

二.传递参数

cpp 复制代码
#include <windows.h>
#include <stdio.h>

DWORD WINAPI tFunction(LPVOID lpParam){
	int* value = (int*)lpParam;//获取传送的数据
	printf("%d",*value);
	Sleep(1000);//这里等待的时候,tFunction2的内容已经跑完了 ,验证了多线程在正常工作 
	return 0;
}

DWORD WINAPI tFunction2(LPVOID lpParam){
	printf("222");
	return 0;
}

int main(){
	int data=100;
	HANDLE hThread=CreateThread(NULL,0,tFunction,&data,0,NULL);//这里&data就是要传递的参数 
	HANDLE hThread2=CreateThread(NULL,0,tFunction2,NULL,0,NULL);
	WaitForSingleObject(hThread,INFINITE);
	WaitForSingleObject(hThread2,INFINITE);
	CloseHandle(hThread);
	CloseHandle(hThread);
	return 0;
}

附:传递结构体

这个比传递简单数据更实用

cpp 复制代码
#include<windows.h>
#include<stdio.h>

typedef struct{
	int id;
	char name[50];
}mPerson;

DWORD WINAPI tFunction(LPVOID lpParam){
	mPerson* person = (mPerson*)lpParam;
	printf("id:%d\nname:%s",person->id,person->name);
	return 0;
}

int main(){
	mPerson person1={1,"pig"};//初始化
	HANDLE hThread = CreateThread(NULL,0,tFunction,&person1,0,NULL);//传递结构体数据
	WaitForSingleObject(hThread,INFINITE);
	CloseHandle(hThread);
	return 0; 
}

三.互斥锁(Mutex) 重要!

我之前写的一个程序就是少了互斥锁,导致一直出bug,几个线程之间会抢资源

1.创建互斥锁

cpp 复制代码
HANDLE hMutex = CreateMutex(
    NULL,      // 安全属性,填NULL就行
    FALSE,     // 是否初始拥有(FALSE表示初始不锁定)
    NULL       // 名字(NULL表示无名)
);

2.加锁

cpp 复制代码
WaitForSingleObject(hMutex, INFINITE);
// 如果锁被占用,线程会在这里等待直到获得锁

3.解锁

cpp 复制代码
ReleaseMutex(hMutex);
// 释放锁,让其他等待的线程可以进入

4.实战测试

cpp 复制代码
#include<windows.h>
#include<stdio.h>

HANDLE hMutex;//创建互斥锁

DWORD WINAPI print111(LPVOID lpParam){
	WaitForSingleObject(hMutex,INFINITE);//等待
	printf("111\n");
	Sleep(100);
	printf("1111\n");
	Sleep(200);
	printf("11111\n");
	ReleaseMutex(hMutex);//释放锁 
	
	return 0;
}

DWORD WINAPI print222(LPVOID lpParam){
	WaitForSingleObject(hMutex,INFINITE);//等待
	printf("222\n");
	Sleep(100);
	printf("2222\n");
	Sleep(200);
	printf("22222\n");
	ReleaseMutex(hMutex);//释放锁 
	
	return 0;
}


int main(){
	hMutex = CreateMutex(NULL,FALSE,NULL);//FALSE表示初始不锁定
	
	HANDLE hThread1=CreateThread(NULL,0,print111,NULL,0,NULL);
	HANDLE hThread2=CreateThread(NULL,0,print222,NULL,0,NULL);
	
	WaitForSingleObject(hThread1,INFINITE);
	WaitForSingleObject(hThread2,INFINITE);
	
	CloseHandle(hThread1);
	CloseHandle(hThread2);
	CloseHandle(hMutex);//互斥锁也是一个句柄,最后记得关掉 
} 

运行结果:

cpp 复制代码
111
1111
11111
222
2222
22222

这里有个很有趣的现象,如果多运行几次,结果会出现不同:

cpp 复制代码
第一次:
111
1111
11111
222
2222
22222
第二次:
111
1111
11111
222
2222
22222
第三次:
222
2222
22222
111
1111
11111
第四次:
111
1111
11111
222
2222
22222

为什么有时线程2会先运行?说明线程2先获得了互斥锁,关键原因是主程序继续运行

cpp 复制代码
WaitForSingleObject(hThread1,INFINITE);
...(这里接着创建了hThread2)

++Windows调度器决定了哪个线程先运行(线程启动需要时间,可能只有几毫秒),在我这里,线程2先被调度运行(线程2在系统几毫秒甚至几微秒的调度时间里,抢先线程1获得了执行机会,体现了多线程调度的随机性)++

如果去掉互斥锁会怎么样:

cpp 复制代码
#include<windows.h>
#include<stdio.h>

DWORD WINAPI print111(LPVOID lpParam){
	printf("111\n");
	Sleep(100);
	printf("1111\n");
	Sleep(200);
	printf("11111\n");
	
	return 0;
}

DWORD WINAPI print222(LPVOID lpParam){
	printf("222\n");
	Sleep(100);
	printf("2222\n");
	Sleep(200);
	printf("22222\n");
	
	return 0;
}


int main(){
	
	HANDLE hThread1=CreateThread(NULL,0,print111,NULL,0,NULL);
	HANDLE hThread2=CreateThread(NULL,0,print222,NULL,0,NULL);
	
	WaitForSingleObject(hThread1,INFINITE);
	WaitForSingleObject(hThread2,INFINITE);
	
	CloseHandle(hThread1);
	CloseHandle(hThread2);
} 

运行结果:

cpp 复制代码
222
111
2222
1111
11111
22222

执行结果已经乱了,这就体现了互斥锁的重要性

四.其他技巧

1.设置线程优先级

cpp 复制代码
// Windows线程优先级(从低到高)
THREAD_PRIORITY_IDLE          // 空闲优先级(最低)
THREAD_PRIORITY_LOWEST        // 最低
THREAD_PRIORITY_BELOW_NORMAL  // 低于正常
THREAD_PRIORITY_NORMAL        // 正常(默认)
THREAD_PRIORITY_ABOVE_NORMAL  // 高于正常
THREAD_PRIORITY_HIGHEST       // 最高
THREAD_PRIORITY_TIME_CRITICAL // 时间关键(最高,几乎实时)

实例:

cpp 复制代码
#include<windows.h>
#include<stdio.h> 

HANDLE hMutex;
int counter1=0,counter2=0;

DWORD WINAPI lowPriority(LPVOID lpParam){
	while(1){
		WaitForSingleObject(hMutex,INFINITE);
		counter1++;//统计执行次数 
		ReleaseMutex(hMutex);
		//Sleep(1);//稍微让出cpu(Sleep的时间约大,优先级高的线程与优先级低的线程差距越小,因为Sleep强制让出了cpu,给了另一个线程机会) 
	}
}
DWORD WINAPI highPriority(LPVOID lpParam){
	while(1){
		WaitForSingleObject(hMutex,INFINITE);
		counter2++;//统计执行次数 
		ReleaseMutex(hMutex);
		//Sleep(1);
	
	}
}

int main(){
	
	hMutex = CreateMutex(NULL,FALSE,NULL);
	
	HANDLE hLow=CreateThread(NULL,0,lowPriority,NULL,0,NULL);
	HANDLE hHigh=CreateThread(NULL,0,highPriority,NULL,0,NULL);
	
	SetThreadPriority(hLow,THREAD_PRIORITY_LOWEST);//最低优先级
	SetThreadPriority(hHigh,THREAD_PRIORITY_HIGHEST);//最高优先级

	Sleep(1000);
	
	printf("low counter:%d\n",counter1);
	printf("high counter:%d",counter2);
	
	CloseHandle(hLow);
	CloseHandle(hHigh);
	CloseHandle(hMutex); 
	
	return 0;
}

这里会有误差,有时候低优先级线程统计数比高优先级线程统计数还高,大家可以自行测试一下

2.强制终止线程

cpp 复制代码
#include<stdio.h>
#include<windows.h>

DWORD WINAPI thread(LPVOID lpParam){
	printf("111");
	Sleep(1000);
	printf("222");
	Sleep(1000);
	printf("333");
	
	return 0;
}

int main(){
	HANDLE hThread = CreateThread(NULL,0,thread,NULL,0,NULL);
	Sleep(100);
	TerminateThread(hThread,0);//强制终止线程(危险,如果线程里的互斥锁没释放,可能导致其它线程死锁) 
	
	return 0;
} 

不想写了,睡觉去

相关推荐
~kiss~1 小时前
CrossFlowDG 跨域泛化学习二
学习
t-think1 小时前
深入了解指针(3)
c语言·算法
hef2881 小时前
利用C 图形界面展示MATLAB算法的高效混合编程实践
windows·算法·matlab
.千余1 小时前
【Linux】Socket编程UDP
linux·运维·服务器·开发语言·网络协议·学习·udp
Shadow(⊙o⊙)1 小时前
qt信号和槽链接的接入与断开
开发语言·前端·c++·qt·学习
想你依然心痛1 小时前
HarmonyOS 6 悬浮导航 + 沉浸光感:打造鸿蒙智能体驱动的沉浸式编程学习伴侣
学习·华为·ar·harmonyos·智能体
Harm灬小海1 小时前
【云计算学习之路】企业常用服务搭建:构建Apache WEB服务器
运维·服务器·学习·云计算·apache
linbaiwan6661 小时前
PD和QC快充协议电压诱骗(取电)芯片:USB-C口支持PD,USB-A口支持QC
c语言·开发语言
灰灰勇闯IT1 小时前
TorchAir:PyTorch 跑在昇腾NPU上的桥梁
学习·aigc