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;
} 

不想写了,睡觉去

相关推荐
捷瑞电子工坊1 天前
嵌入式秋招面经:5大核心模块高频考题与实战避坑总结
c语言·stm32·嵌入式工程师·rtos·通信协议·嵌入式面试
蒸蒸yyyyzwd1 天前
秋招不熟悉力扣学习笔记1
笔记·学习·leetcode
天空'之城1 天前
C 语言工业级通用组件手写 30:安全内存拷贝组件
c语言·内存拷贝·工业级组件·安全内存操作
LuminousCPP1 天前
数据结构-双向循环链表
c语言·数据结构·笔记·链表
小弥儿1 天前
GitHub今日热榜 | 2026-08-11:图原生基础设施首日登顶
学习·开源·github
小僧景贤1 天前
嵌入式C语言 第二篇:基础语法|嵌入式C与标准C的核心差异
c语言·开发语言·嵌入式c语言
for_ever_love__1 天前
python基础语法学习: 数据容器
windows·python·学习
云空1 天前
《电子专业完整学习路线图(分两套:本科四年版 / 零基础自学速成版)》
科技·学习·学习方法·高考
min(a,b)1 天前
学习第16天:LangGraph 与 Agent 工作流编排
学习
woshihuanglaoshi1 天前
鸿蒙技术进阶全景高级成长体系:从初中级到架构师的技能树/学习路径/项目实战/认证体系系统性方法论
学习·华为·harmonyos