Windows线程开发
Windows线程开发
1.线程基础
Windows线程是可以执行的代码实例。系统十一线程为单位调度程序。一个程序当中可以有多个线程,实现多个任务的处理。
Windows线程的特点:
- 线程都具有1个ID
- 每个线程都具有自己的内存栈
- 同一进程中的线程使用同一个地址空间
线程的调度
操作系统将CPU的执行时间划分成时间片,依次根据时间片执行不同的线程。线程轮询:线程A->线程B->线程A......
2.创建线程
创建线程
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, //安全属性
SIZE_T dwStackSize, //线程栈的大小
LPTHREAD_START_ROUTINE lpStartAddress, //线程处理函数的函数地址
LPVOID lpParameter, //传递给线程处理函数的参数
DWORD dwCreationFlags, //线程创建方式
LPDWORD lpThreadId //创建成功,返回线程的ID
);创建成功,返回线程句柄
定义线程处理函数
DWORD WINAPI ThreadProc(
LPVOID lpParameter //创建线程时,传递给线程的参数
);
例子:
#include <Windows.h>
#include <stdio.h>
DWORD CALLBACK ThreadProc(LPVOID param){
char* pszText = (char*) param;
while(1){
printf("%s\n",pszText);
Sleep(1000);
}
return 0;
}
int main(){
DWORD pid = 0;
char* pszText="******";
HANDLE hThread = CreateThread(NULL,0,ThreadProc,pszText,0,&pid);
getchar();
return 0;
}
3.线程挂起/销毁
挂起
DWORD SuspendThread(
HANDLE hThread //handle to thread
);
唤醒
DWORD ResumeThread(
HANDLE hThread //handle to thread
);
例子:
#include <Windows.h>
#include <stdio.h>
DWORD CALLBACK ThreadProc(LPVOID param){
char* pszText = (char*) param;
while(1){
printf("%s\n",pszText);
Sleep(1000);
}
return 0;
}
DWORD CALLBACK ThreadProc2(LPVOID param){
char* pszText = (char*) param;
while(1){
printf("%s\n",pszText);
Sleep(1000);
}
return 0;
}
int main(){
DWORD pid = 0;
char* pszText="<<<<<<";
HANDLE hThread = CreateThread(NULL,0,ThreadProc,pszText,0,&pid); //创建的线程立即执行
char* pszText2 = ">>>>>>";
HANDLE hThread2 = CreateThread(NULL,0,ThreadProc2,pszText2,CREATE_SUSPENDED,&pid); //创建的线程挂起
getchar();
SuspendThread(hThread);
ResumeThread(hThread2);
getchar();
return 0;
}
4.线程相关操作
结束指定线程
BOOL TerminateThread(
HANDLE hTread, //handle to thread
DWORD dwExitCode //exit code
);
结束函数所在的线程
VOID ExitThread(
DWORD dwExitCode //exit code for this thread
);
获取当前线的ID
GetCurrentThreadId();
获取当前线程的句柄
GetCurrentThread();
等候单个句柄有信号
VOID WaitForSingleObject(
HANDLE handle, //句柄BUFF的地址
DWORD dwMillseconds //等候时间INFINITE(无限大)
);
同时等候多个句柄有信号
DWORD WaitForMultipleObjects(
DWORD nCount, //句柄数量
CONST HANDLE *lpHandles, //句柄BUFF的地址
BOOL bWaitAll, //等候方式
DWORD dwMillisenconds //等候时间INFINITE
);
bWaitAll - 等候方式:
TRUE - 表示所有句柄都有信号,才结束等候
FALSE - 表示句柄中只要有1个有信号,就结束等候
5.线程同步
5.1 原子锁
相关问题
多个线程对同一个数据进行原子操作,会产生结果丢失。比如执行++运算时。
错误代码分析
当线程A执行g_value++时,如果线程切换时间正好是线程A将值保存到g_value之前线程B继续执行g_value++,那么当线程A再次切换回来之后,会将原来线程A保存的值保存到g_value上,线程B进行的加法操作被覆盖。
使用原子锁函数
InterlockedIncrement
InterlockedDecrement
InterlockedCompareExchange
InterlockedExchange
...
原子锁的实现:直接对数据所在的内存操作,并且 在任何一个瞬间只能有一个线程访问。
5.2 互斥
相关的问题
多线程下代码或资源的共享使用。
互斥的使用
创建互斥
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, //安全属性
BOOL bInitialOwner, //初始的拥有者 TRUE/FALSE
LPCTSTR lpName //命名
); 创建成功返回互斥句柄
等候互斥
WaitFor... 互斥的等候遵循谁先等候谁先获取。
释放互斥
BOOL ReleaseMutex(
HANDLE hMutex //handle to mutex
);
关闭互斥句柄
CloseHandle(
HANDLE hMutex
);
例子:
#include <Windows.h>
#include <stdio.h>
HANDLE g_hMutex = 0; //获得互斥句柄
DWORD CALLBACK ThreadProc(LPVOID param){
char* pszText = (char*) param;
while(1){
/*printf("%s\n",pszText);
Sleep(1000);*/
WaitForSingleObject(g_hMutex,INFINITE);
for(int i = 0; i < strlen(pszText); i++){
printf("%c",pszText[i]);
Sleep(125);
}
printf("\n");
ReleaseMutex(g_hMutex);
}
return 0;
}
DWORD CALLBACK ThreadProc2(LPVOID param){
char* pszText = (char*) param;
while(1){
/*printf("%s\n",pszText);
Sleep(1000);*/
WaitForSingleObject(g_hMutex,INFINITE);
for(int i = 0; i < strlen(pszText); i++){
printf("%c",pszText[i]);
Sleep(125);
}
printf("\n");
ReleaseMutex(g_hMutex);
}
return 0;
}
int main(){
g_hMutex = CreateMutex(NULL,FALSE,NULL);
DWORD pid = 0;
char* pszText="<<<<<<";
HANDLE hThread = CreateThread(NULL,0,ThreadProc,pszText,0,&pid); //创建的线程立即执行
char* pszText2 = ">>>>>>";
HANDLE hThread2 = CreateThread(NULL,0,ThreadProc2,pszText2,0,&pid);
getchar();
CloseHandle(g_hMutex);
return 0;
}
5.3 事件
相关问题
程序之间的通知的问题。
事件的使用
创建事件
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, //安全属性
BOOL bManualReset,
//事件重置(复位)方式,TRUE手动,FALSE自动
BOOL bInitialState, //事件初始状态,TRUE有信号
LPCTSTR lpName //事件命名
);创建成功返回事件句柄
等候事件
WaitForSingleObject/WaiteForMultipleObjects触发事件(将事件设置成有信号状态)
BOOL SetEvent(
HANDLE hEvent //handle to event
);
复位事件(将事件设置成无信号状态)
BOOL ResetEvent(
HANDLE hEvent //handle to event
);
关闭事件
CloseHandle(HANDLE hEvent);
小心事件的死锁
例子:
#include <Windows.h>
#include <stdio.h>
HANDLE g_hEvent = 0; //获得事件句柄
DWORD CALLBACK PrintProc(LPVOID param){
while(1){
WaitForSingleObject(g_hEvent,INFINITE);
ResetEvent(g_hEvent);
printf("*********\n");
}
return 0;
} DWORD CALLBACK CtlProc(LPVOID param){
while(1){
Sleep(1000);
SetEvent(g_hEvent);
}
return 0;
}
int main(){
g_hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
DWORD pid = 0;
HANDLE hThread[2] = {0};
hThread[0] = CreateThread(NULL,0,PrintProc,NULL,0,&pid);
hThread[0] = CreateThread(NULL,0,CtlProc,NULL,0,&pid);
WaitForMultipleObjects(2,hThread,TRUE,INFINITE);
getchar();
CloseHandle(g_hEvent);
return 0;
}
5.4 信号量
相关的问题
类似于事件,解决通知的相关问题。但提供一个计数器,可以设置次数。
信号量的使用
创建信号量
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, //安全属性
LONG lInitialCount, //初始化信号量数量
LONG lMaximumCount, //信号量的最大值
LPCTSTR lpName //命名
); 创建成功返回信号量句柄
等候信号量
WaitFor... 每等候通过一次,信号量的信号减1,直到为0阻塞
给信号量指定计数值
BOOL ReleaseSemaphore(
HANDLE hSemaphore, //信号量句柄
LONG lReleaseCount, //释放数量
LPLONG lpPreviousCount //释放前原来信号量的数量,可以为NULL
);
关闭句柄
CloseHandle(HANDLE handle);
#include <Windows.h>
#include <stdio.h>
HANDLE g_hSema = 0; //信号量句柄
DWORD CALLBACK TestProc(LPVOID param){
while(1){
WaitForSingleObject(g_hSema,INFINITE);
printf("*********\n");
}
return 0;
} int main(){
g_hSema = CreateSemaphore(NULL,3,10,NULL);
DWORD pid = 0;
HANDLE hThread = CreateThread(NULL,0,TestProc,NULL,0,&pid);
getchar();
ReleaseSemaphore(g_hSema,5,NULL);
WaitForSingleObject(hThread,INFINITE);
CloseHandle(g_hSema);
return 0;
}
Windows线程开发的更多相关文章
- Kinect for Windows SDK开发入门(15):进阶指引 下
Kinect for Windows SDK开发入门(十五):进阶指引 下 上一篇文章介绍了Kinect for Windows SDK进阶开发需要了解的一些内容,包括影像处理Coding4Fun K ...
- Windows Phone开发(46):与Socket有个约会
原文:Windows Phone开发(46):与Socket有个约会 不知道大家有没有"谈Socket色变"的经历?就像我一位朋友所说的,Socket这家伙啊,不得已而用之.哈,S ...
- windows 驱动开发入门——驱动中的数据结构
最近在学习驱动编程方面的内容,在这将自己的一些心得分享出来,供大家参考,与大家共同进步,本人学习驱动主要是通过两本书--<独钓寒江 windows安全编程> 和 <windows驱动 ...
- C# Windows服务开发从入门到精通
一.课程介绍 大家都知道如果想要程序一直运行在windows服务器上,最好是把程序写成windows服务程序:这样程序会随着系统的自动启动而启动,自动关闭而关闭,不需要用户直接登录,直接开机就可以启动 ...
- Windows线程+进程通信
一 Windows线程进程 1)定义 按照MS的定义, Windows中的进程简单地说就是一个内存中的可执行程序, 提供程序运行的各种资源. 进程拥有虚拟的地址空间, 可执行代码, 数据, 对象句柄集 ...
- Windows内核开发-4-内核编程基础
Windows内核开发-4-内核编程基础 这里会构建一个简单但是完整的驱动程序和一个客户端,部署内核执行一些平时user下无法执行的操作. 将通过以下内容进行讲解: 1 介绍 2 驱动初始化 3 Cr ...
- C++第三十三篇 -- 研究一下Windows驱动开发(一)内部构造介绍
因为工作原因,需要做一些与网卡有关的测试,其中涉及到了驱动这一块的知识,虽然程序可以运行,但是不搞清楚,心里总是不安,觉得没理解清楚.因此想看一下驱动开发.查了很多资料,看到有人推荐Windows驱动 ...
- Windows内核开发-5-(2)-内核模式调试
Windows内核开发-5-(2)-内核模式调试 普通用户模式的调试,采取的是给进程添加一个线程来挂起断点,作为一个调试器的线程在进程中使用.照这样来类推,对操作系统调试相当于添加一个进程来限制操作系 ...
- Windows内核开发-6-内核机制 Kernel Mechanisms
Windows内核开发-6-内核机制 Kernel Mechanisms 一部分Windows的内核机制对于驱动开发很有帮助,还有一部分对于内核理解和调试也很有帮助. Interrupt Reques ...
- Windows内核开发-10-监听对象
Windows内核开发-10-监听对象 Windows内核除了可以监听进程,线程.dll还可以监听特定的对象和注册表.这里先讲一下监听对象. 监听对象 内核提供了一种可以监听对特定的对象类型的句柄进行 ...
随机推荐
- decltype关键词
简述 decltype 是 C++11 新增的一个关键字,它和 auto 的功能一样,都用来在编译时期进行自动类型推导. decltype 是"declare type"的缩写,译 ...
- AcWing 190. 字串变换
原题连接:AcWing 190. 字串变换 题意: 已知有两个字串 \(A, B\) 及一组字串变换的规则(至多 \(6\) 个规则): \(A_1→B_1\) \(A_2→B_2\) \(-\) 规 ...
- 自定义springboot-starter 动态数据源
自定义springboot-starter 动态数据源 如果使用的是spring或springboot框架,spring提供了一个实现动态数据源的一个抽象类AbstractRoutingDataSou ...
- The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission,iphone手机video标签报错
The request is not allowed by the user agent or the platform in the current context, possibly becaus ...
- Detecting Unknown Encrypted Malicious Traffic in Real Time via Flow Interaction Graph Analysis
1 前言 1.1 标题 Detecting Unknown Encrypted Malicious Traffic in Real Time via Flow Interaction Graph An ...
- PolarCTF-2023冬季个人挑战赛 WP
Crypto 数星星 题目 小明暗恋小红很久了,终于在一个月黑风高的夜晚,决定约她出去数星星.小明数着数着,数出了一串数字,3,6,10,12,15,他觉得这是爱情的关键,思考了整整一晚上,小红很生气 ...
- MongoDB中的分布式集群架构
MongoDB 中的分布式集群架构 前言 Replica Set 副本集模式 副本集写和读的特性 Sharding 分片模式 分片的优势 MongoDB 分片的组件 分片键 chunk 是什么 分片的 ...
- Linux常用命令(持续完善中......)
1.查看内存 top 2.查看磁盘存储情况 df -h 3.查看端口占用情况 netstat -tunlp | grep 端口号 4.查看报告系统运行时长及平均负载 uptime 5.查看进程 ps ...
- SpringBoot项目整合微信登录
一.开通微信登录 去微信开发者平台 1.注册 2.邮箱激活 3.完善开发者资料 4.开发者资质认证 准备营业执照,1-2个工作日审批.300元 5.创建网站应用 6.提交审核,7个工作日审批 7.熟悉 ...
- 解密Prompt系列21. LLM Agent之再谈RAG的召回信息密度和质量
话接上文的召回多样性优化,多路索引的召回方案可以提供更多的潜在候选内容.但候选越多,如何对这些内容进行筛选和排序就变得更加重要.这一章我们唠唠召回的信息密度和质量.同样参考经典搜索和推荐框架,这一章对 ...