Windows线程

Windows线程
线程基础
  • Windows线程是可以执行的代码的实例。

    系统是以线程为单位调度程序,一个程序中可以有多个线程,实现多任务的处理。主线程只能有一个。

  • Windows线程的特点

    1. 线程都具有1个ID
    2. 每个线程都具有自己的内存栈,其余的共享。
    3. 同一进程中的线程使用同一个地址空间。(除了栈空间)
  • 线程的调度

    操作系统将CPU的执行时间划分为时间片,依次根据时间片执行不同的线程。

    线程轮询: 线程A -> 线程B ->线程A …

创建线程
  • 创建线程

    HANDLE CreateThread(
    	LPSECURITY_ATTRIBUTES lpThreadAttributes , // 安全属性,已废弃, NULL
        SIZE_T dwStackSize, // 线程栈的大小  按1M对齐,最少1M
        LPTHREAD_START_ROUTINE lpStartAddress, // 线程处理函数的函数地址,自己定义由系统调用
        LPVOID lpParameter, // 传递给线程处理函数的参数
        DWORD dwCreationFlags, // 线程的创建方式(立即执行&挂起方式)
        // 0 -> 立即启动
        // CREATE_SUSPENDED -> 挂起
        LPDWORD lpThreadId // 创建成功,返回线程的ID
    ); // 创建成功,返回线程句柄  ( 线程句柄和线程ID都可以代表线程 )
    
  • 定义线程处理函数

    DWORD WINAPI ThreadProc(
    	LPVOID lpParameter // 创建线程时,传递给线程的参数
    );
    

Demo

#include <windows.h>
#include <stdio.h>
DWORD CALLBACK TestProc(LPVOID pParam){
   char * pszText = (char *) pParam;
   printf("%s",pszText);
}
int main(){
    DWORD nID = 0;
    char * pszText = "******";
    HANDLE hThread = CreateThread(NULL,0,TestProc,pszText,0,&nID);
	getchar();
	return 0;
}

子线程正常执行->要保证主线程不结束

销毁线程
  • 挂起

    DWORD SuspendThread(
    	HANDLE hThread // 线程句柄
    );
    
  • 唤醒

    DWORD ResumeThread(
    	HANDLE hThread  // 线程句柄
    );
    
  • 结束指定线程

    BOOL TerminateThread(
    	HANDLE hThread, // 线程句柄
        DWORD dwExitCode // 退出码,一般没用
    );
    
  • 结束函数所在的线程

    VOID ExitThread(
    	DWORD dwExitCode // 退出码,没有实际意义
    );
    // 自杀 -> 只能干掉调用的线程
    
线程相关操作
  • 获取当前线程ID

    GetCurrentThreadId();
    
  • 获取当前线程的句柄

    GetCurrentThread();
    
  • 等候单个句柄有信号

    VOID WaitForSingleObject(
    	HANDLE handle , // 句柄BUFF的地址
        DWORD dwMilliseconds // 最长等候时间 ms
        // INFINITE 一直等待
    );
    // 有信号时会立即返回
    // 没有信号会阻塞
    

    线程句柄是可等候句柄: 有信号和无信号状态

  • 同时等候多个句柄有信号

    DWORD WaitForMultipleObject(
    	DWORD nCount, // 句柄数量
        CONST HANDLE *lpHandles, // 句柄BUFF的地址
        BOOL bWaitAll, // 等候方式
        // TRUE : 所有句柄都有信号才会返回
        // FALSE: 只要有一个有信号就返回
        DWORD dwMilliseconds // 等候时间  INFINITE
    );
    

    可等候句柄

  • 线程信号

    • 当线程处于执行状态时,线程无信号
    • 当线程结束那刻,线程有信号
线程同步
原子锁
  • 当多个线程对同一个数据进行原子操作,会产生结果丢失,比如算术运算

  • 使用原子锁函数

    InterlockedIncrement   // ++ 操作符
    InterlockedDecrement   // --
    InterlockedCompareExchange   // 三目运算符 
    InterlockedExchange    // = 赋值
    

    原子锁的实现,直接对数据所在的内存操作,并且任何一个瞬间只能有一个线程访问。

  • 只能对运算符加锁,效率高,但是麻烦

互斥锁
  • 相关问题

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

  • 互斥的使用

    1. 创建互斥

      HANDLE CreateMutex(
      	LPSECURITY_ATTRIBUTES lpMutexAttributes, // 安全数据(NULL)
          BOOL bInitialOwner, // 初始的拥有者 TRUE/FALSE
          // TRUE: 哪个线程创建哪个线程拥有
          // FALSE: 都不拥有
          LPCTSTR lpName // 命名
      ); // 创建成功返回互斥句柄
      // 互斥句柄,也是可等候句柄
      
      • 在任何时间点上只有一个线程拥有互斥, 独占性和排他性

      • 当任何线程都不拥有互斥,互斥有信号,任何一个线程拥有互斥,互斥就没有信号

    2. 等候互斥

      WaitFor… 函数

      互斥的等候遵循谁先等候谁先获得

      也就是加锁

    3. 释放互斥

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

      CloseHandle
      

demo

#include <windows.h>
#include <stdio.h>

HANDLE hmutex; // 接收互斥句柄 

DWORD CALLBACK TestProc(LPVOID pParam){
   char * pszText = (char *) pParam;
   int i ;
   while(1){
   	    WaitForSingleObject(hmutex,INFINITE);
	    for(i = 0;i<strlen(pszText);i++){
	   		printf("%c",pszText[i]);
	   		Sleep(125);
	   }
	   printf("\n");
	   ReleaseMutex(hmutex); 
   } 
}
int main(){
	hmutex = CreateMutex(NULL,FALSE,NULL); 
    DWORD nID1 = 0;
    DWORD nID2 = 0;
    char * pszText1 = "******";
    char * pszText2 = "------";
    HANDLE hThread1 = CreateThread(NULL,0,TestProc,pszText1,0,&nID1);
    HANDLE hThread2 = CreateThread(NULL,0,TestProc,pszText2,0,&nID2);
	getchar();
	CloseHandle(hmutex);
	return 0;
}
事件
  • 相关问题

    线程之间的通知问题

  • 事件的使用

    1. 创建事件

      HANDLE CreateEvent(
      	LPSEURITY_ATTRIBUTES lpEventAttributes, // 安全属性
          BOOL bManualReset, // 事件重置(复位)方式 有信号 -> 无信号
          // TRUE  手动
          // FALSE 自动 --> 读取信号一次就会自动复位
          // 触发 无信号 ->有信号
          BOOL bInitialState ,// 事件初始状态,TRUE 有信号
          LPCTSTR lpName // 事件命名,可以为空
      );// 创建成功返回事件句柄
      

      可等候句柄

      事件的有信号无信号可控制

    2. 等候事件

      WaitForSingleObject  / WaitForMultipleObjects
      // 自动复位方式,会自动复位
      
    3. 触发事件( 将事件设置为有信号状态)

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

      BOOL ResetEvent(
      	HANDLE hEvent
      );
      
    5. 关闭事件

      CloseHandle
      

要小心事件的死锁问题

demo

#include <windows.h>
#include <stdio.h>
HANDLE g_hEvent = 0; // 接收事件句柄

DWORD CALLBACK PrintProc(LPVOID pParam){
	while(1){
		WaitForSingleObject(g_hEvent,INFINITE); // 等待信号 
		ResetEvent(g_hEvent); 
		printf("......\n");
	}
}

DWORD CALLBACK CtrlProc(LPVOID pParam){
	while(1){
		Sleep(1000);
		SetEvent(g_hEvent);
	}
} 
int main(){
	g_hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
	DWORD nID = 0;
	HANDLE hThread[2] = {0};
	hThread[0] = CreateThread(NULL,0,PrintProc,NULL,0,&nID); 
	hThread[1] = CreateThread(NULL,0,CtrlProc,NULL,0,&nID);
	WaitForMultipleObjects(2,hThread,TRUE,INFINITE);
	CloseHandle(g_hEvent);
	return 0; 
}
信号量
  • 相关的问题

    作用类似于事件,解决通知的相关问题。

    提供一个计数器,可以设置次数

  • 信号量的使用

    1. 创建信号量

      HANDLE CreateSemaphore(
      	LPSECTRITY_ATTRIBUTES lpSemaphoreAttributes, // 安全属性
          LONG lInitialCount, // 初始化信号量数量
          // 信号量计数值为0时,没有信号
          // 信号量计数值不为0,有信号
          LONG lMaximumCount, // 信号量最大个数
          LPCTSTR lpName // 命名
      );// 创建成功返回信号量句柄
      

      可等候句柄

    2. 等候信号量

      WaitFor ...
      // 每等候通过一次,信号量的信号减1,直到为0阻塞
      
    3. 给信号量指定计数值

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

      CloseHandle
      

demo

#include <windows.h>
#include <stdio.h>
HANDLE g_hSema = 0;// 保存信号量句柄

DWORD CALLBACK TestProc(LPVOID pParam){
	while(1){
		WaitForSingleObject(g_hSema,INFINITE);
		printf("*****\n");
	}
}
 
int main(){
	g_hSema = CreateSemaphore(NULL,3,10,NULL);
	DWORD nID = 0;
	HANDLE hThread = CreateThread(NULL,0,TestProc,NULL,0,&nID);
	getchar();
	ReleaseSemaphore(g_hSema,5,NULL);
	WaitForSingleObject(hThread,INFINITE);
	CloseHandle(g_hSema);	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暴风雨中的白杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值