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. 28. 干货系列从零用Rust编写正反向代理,项目日志的源码实现

    wmproxy wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,内网穿透,后续将实现websocket代理等,会将实现 ...

  2. OpenCL任务调度基础介绍

    当前,科学计算需求急剧增加,基于CPU-GPU异构系统的异构计算在科学计算领域得到了广泛应用,OpenCL由于其跨平台特性在异构计算领域渐为流行,其调度困难的问题也随之暴露,传统的OpenCL任务调度 ...

  3. 快速下载vscode、git

    在官网下载vscode太慢,解决方式: http://vscode.cdn.azure.cn/stable/ea3859d4ba2f3e577a159bc91e3074c5d85c0523/VSCod ...

  4. 【uniapp】【微信小程序】【外包杯】如何创建分包

    意义:分包可以减少小程序数次启动时的加载时间 1.创建分包的根目录 2.在page.json中,和pages节点平级的位置声明节点,用来定义分包的相关结构 3.在subpkg目录上新建页面 4.完成了

  5. 路径规划算法 - 求解最短路径 - Dijkstra(迪杰斯特拉)算法

    Dijkstra(迪杰斯特拉)算法的思想是广度优先搜索(BFS) 贪心策略. 是从一个顶点到其余各顶点的最短路径算法,节点边是不各自不同的权重,但都必须是正数 如果是负数,则需要 Bellman-Fo ...

  6. Pipeline模式应用

    本文记录Pipeline设计模式在业务流程编排中的应用 前言 Pipeline模式意为管道模式,又称为流水线模式.旨在通过预先设定好的一系列阶段来处理输入的数据,每个阶段的输出即是下一阶段的输入. 本 ...

  7. java制作游戏,如何使用libgdx,入门级别教学

    第一步,进入libgdx的官网.点击get started 进入这个页面,点击setup a project 进入这个页面直接点击,Generate a project. 点击下载,下载创建工具 它会 ...

  8. Linux笔记02: Linux环境_2.1虚拟机软件VMware

    2.1 虚拟机软件VMware 如果直接在计算机上安装多个操作系统,同一个时刻只能运行一个操作系统,切换系统需重启计算机.VMware可以使用户在一台计算机上同时运行多个操作系统(如Windows.L ...

  9. 【译】Visual Studio 17.8 中我最喜欢的特性

    对于 Visual Studio 团队来说,这是忙碌的一周,他们准备了 Ignite 和 .NET Conf,并发布了最新版本的 Visual Studio 2022,即17.8版本.有很多很酷的新功 ...

  10. 吉特日化MES & 医药行业相关专业术语汇总