Windows线程开发

1.线程基础

  • Windows线程是可以执行的代码实例。系统十一线程为单位调度程序。一个程序当中可以有多个线程,实现多个任务的处理。

  • Windows线程的特点:

    1. 线程都具有1个ID
    2. 每个线程都具有自己的内存栈
    3. 同一进程中的线程使用同一个地址空间
  • 线程的调度

    操作系统将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 互斥

  • 相关的问题

    ​ 多线程下代码或资源的共享使用。

  • 互斥的使用

    1. 创建互斥

      HANDLE CreateMutex(
      LPSECURITY_ATTRIBUTES lpMutexAttributes, //安全属性
      BOOL bInitialOwner, //初始的拥有者 TRUE/FALSE
      LPCTSTR lpName //命名
      ); 创建成功返回互斥句柄
    2. 等候互斥

      ​ WaitFor... 互斥的等候遵循谁先等候谁先获取。

    3. 释放互斥

      BOOL ReleaseMutex(
      HANDLE hMutex //handle to mutex
      );
    4. 关闭互斥句柄

      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 事件

  • 相关问题

    ​ 程序之间的通知的问题。

  • 事件的使用

    1. 创建事件

      HANDLE CreateEvent(
      LPSECURITY_ATTRIBUTES lpEventAttributes, //安全属性
      BOOL bManualReset,
      //事件重置(复位)方式,TRUE手动,FALSE自动
      BOOL bInitialState, //事件初始状态,TRUE有信号
      LPCTSTR lpName //事件命名
      );创建成功返回事件句柄
    2. 等候事件

      WaitForSingleObject/WaiteForMultipleObjects

    3. 触发事件(将事件设置成有信号状态)

      BOOL SetEvent(
      HANDLE hEvent //handle to event
      );
    4. 复位事件(将事件设置成无信号状态)

      BOOL ResetEvent(
      HANDLE hEvent //handle to event
      );
    5. 关闭事件

      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 信号量

  • 相关的问题

    ​ 类似于事件,解决通知的相关问题。但提供一个计数器,可以设置次数。

  • 信号量的使用

    1. 创建信号量

      HANDLE CreateSemaphore(
      LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, //安全属性
      LONG lInitialCount, //初始化信号量数量
      LONG lMaximumCount, //信号量的最大值
      LPCTSTR lpName //命名
      ); 创建成功返回信号量句柄
    2. 等候信号量

      WaitFor... 每等候通过一次,信号量的信号减1,直到为0阻塞

    3. 给信号量指定计数值

      BOOL ReleaseSemaphore(
      HANDLE hSemaphore, //信号量句柄
      LONG lReleaseCount, //释放数量
      LPLONG lpPreviousCount //释放前原来信号量的数量,可以为NULL
      );
    4. 关闭句柄

      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线程开发的更多相关文章

  1. Kinect for Windows SDK开发入门(15):进阶指引 下

    Kinect for Windows SDK开发入门(十五):进阶指引 下 上一篇文章介绍了Kinect for Windows SDK进阶开发需要了解的一些内容,包括影像处理Coding4Fun K ...

  2. Windows Phone开发(46):与Socket有个约会

    原文:Windows Phone开发(46):与Socket有个约会 不知道大家有没有"谈Socket色变"的经历?就像我一位朋友所说的,Socket这家伙啊,不得已而用之.哈,S ...

  3. windows 驱动开发入门——驱动中的数据结构

    最近在学习驱动编程方面的内容,在这将自己的一些心得分享出来,供大家参考,与大家共同进步,本人学习驱动主要是通过两本书--<独钓寒江 windows安全编程> 和 <windows驱动 ...

  4. C# Windows服务开发从入门到精通

    一.课程介绍 大家都知道如果想要程序一直运行在windows服务器上,最好是把程序写成windows服务程序:这样程序会随着系统的自动启动而启动,自动关闭而关闭,不需要用户直接登录,直接开机就可以启动 ...

  5. Windows线程+进程通信

    一 Windows线程进程 1)定义 按照MS的定义, Windows中的进程简单地说就是一个内存中的可执行程序, 提供程序运行的各种资源. 进程拥有虚拟的地址空间, 可执行代码, 数据, 对象句柄集 ...

  6. Windows内核开发-4-内核编程基础

    Windows内核开发-4-内核编程基础 这里会构建一个简单但是完整的驱动程序和一个客户端,部署内核执行一些平时user下无法执行的操作. 将通过以下内容进行讲解: 1 介绍 2 驱动初始化 3 Cr ...

  7. C++第三十三篇 -- 研究一下Windows驱动开发(一)内部构造介绍

    因为工作原因,需要做一些与网卡有关的测试,其中涉及到了驱动这一块的知识,虽然程序可以运行,但是不搞清楚,心里总是不安,觉得没理解清楚.因此想看一下驱动开发.查了很多资料,看到有人推荐Windows驱动 ...

  8. Windows内核开发-5-(2)-内核模式调试

    Windows内核开发-5-(2)-内核模式调试 普通用户模式的调试,采取的是给进程添加一个线程来挂起断点,作为一个调试器的线程在进程中使用.照这样来类推,对操作系统调试相当于添加一个进程来限制操作系 ...

  9. Windows内核开发-6-内核机制 Kernel Mechanisms

    Windows内核开发-6-内核机制 Kernel Mechanisms 一部分Windows的内核机制对于驱动开发很有帮助,还有一部分对于内核理解和调试也很有帮助. Interrupt Reques ...

  10. Windows内核开发-10-监听对象

    Windows内核开发-10-监听对象 Windows内核除了可以监听进程,线程.dll还可以监听特定的对象和注册表.这里先讲一下监听对象. 监听对象 内核提供了一种可以监听对特定的对象类型的句柄进行 ...

随机推荐

  1. What is Conjugate complex number(共轭复数)?

    word explain Conjugate 共轭是一个古代汉语词,在农业领域常用, 共轭复数的定义 两个实部相等,虚部互为相反数的复数互为共轭复数. 若Z=a+bi(a,b∈R),则Z*=a-bi( ...

  2. js判断字符串数据类型

    mounted() { this.isJSON('{"key":1232,"a":2},{"key":1232,"a": ...

  3. java读取照片Exif信息到实体类

    前言 1.总共读出来了228个参数信息,但是我挑选了36个我认为比较有价值的参数,弄成了实体类 (其实是因为很多参数我看不明白是啥意思) 2.为了方便,所以实体类里我直接用中文字段了 效果图 导入依赖 ...

  4. 通过 VS Code 优雅地编辑 Pod 内的代码(非 NodePort)

    目录 1. 概述 2. NodePort 方式 3. Ingress 方式 4. 救命稻草 5. 其他 1. 概述 今天聊点啥呢,话说,你有没有想过怎样用 VS Code 连上 K8s 集群内的某个 ...

  5. yarn的常用命令

    yarn 安装 npm install -g yarn 查看版本 yarn -v 开始一个新工程 yarn init 与 npm init 一样通过交互式会话创建一个 package.json yar ...

  6. Kafka核心逻辑介绍

    1.概念 Kafka是最初由Linkedin公司开发,是一个分布式.支持分区的(partition).多副本的(replica)分布式消息系统(kafka2.8.0版本之后接触了对zk的依赖,使用自己 ...

  7. 如何将 Python 项目打包成 exe,另带卸载功能!

    前言 虽然我是做 web 的,但是对 Python 的众多开源项目一直都很关注.像之前的 stable diffusion 的 AI 绘画,和 so-vits-svc 音色替换等源码的部署文档都很完善 ...

  8. python操作mongodb基本使用

    使用pymongo,具体可以参考官方文档: 语法上基本和原生mongodb是一样的,所以非常容易入手... https://pymongo.readthedocs.io/en/stable/tutor ...

  9. Wifi BSSID获取

    代码很简单,通过wifiManager 获取wifiinfo,从而获取bssid, public static String getWifiSSID(Context context) { String ...

  10. 什么是革命性技术eBPF?为什么可观测性领域都得用它

    公众号「架构成长指南」,专注于生产实践.云原生.分布式系统.大数据技术分享. 如果有一种技术可以监控和采集任何应用信息,支持任何语言,并且应用完全无感知,零侵入,想想是不是很激动,那么这个技术是什么呢 ...