C++多线程编程:多线程API介绍

C++多线程编程:什么是多线程?

C++多线程编程:多线程API介绍

C++多线程编程:多线程的同步和互斥

C++多线程编程:多线程同步之临界区 CriticalSection

C++多线程编程:多线程同步之线程死锁

C++多线程编程:同步之信号量 Semaphore

C++多线程编程:同步之互斥量Mutex

C++多线程编程:同步之事件Event

C++多线程编程:同步之PV操作

1. 头文件

#include <Windows.h>

2. CreateThread创建线程

CreateThread function (processthreadsapi.h) - Win32 apps | Microsoft Docs

HANDLE CreateThread(
 LPSECURITY_ATTRIBUTES   lpThreadAttributes,
 SIZE_T                  dwStackSize,
 LPTHREAD_START_ROUTINE  lpStartAddress,
 __drv_aliasesMem LPVOID lpParameter,
 DWORD                   dwCreationFlags,
 LPDWORD                 lpThreadId
);

Create Thread是 Windows ap中在主线程的基础上创建一个新线程。创建成功之后会返回一个 h thread的 handle,且内核对象的计数加1,losehandle之后,引用计数减1,当变为0时,系统删陵内核对象。handle仅仅是线程的一个"标识"。

3. CloseHandle关闭线程句柄

CloseHandle function (handleapi.h) - Win32 apps | Microsoft Docs

BOOL CloseHandle(
 HANDLE hObject
);

4. SuspendThread挂起指定的线程

SuspendThread function (processthreadsapi.h) - Win32 apps | Microsoft Docs

DWORD SuspendThread(
 HANDLE hThread
);

5. ResumeThread恢复被挂起的线程的执行

ResumeThread function (processthreadsapi.h) - Win32 apps | Microsoft Docs

DWORD ResumeThread(
 HANDLE hThread
);

6. Sleep休眠线程的执行

VOID WINAPI Sleep( __in DWORD dwMilliseconds);

dwMilliseconds:毫秒数

7. 示例代码1

#include<windows.h>//线程相关头文件
#include<iostream>
using namespace  std;

//线程处理函数,windows标准调用约定_stdcall
DWORD   WINAPI  ThreadFun ( LPVOID lpThreadParameter );

int  main()
{
  
   DWORD    threadId=0;

   HANDLE hThread=CreateThread(NULL,//设为NULL使用默认安全性
   	0,//如果为0,那么默认将使用与调用该函数的线程相同的栈空间大小。
   	ThreadFun,//线程处理函数,函数名就是函数指针
   	"hello",//向线程函数传入的参数
   	0,//创建后马上运行
   	&threadId);

   if (hThread == NULL)
   {
   	cout << "线程创建失败:" << GetLastError() << endl;
   }

   cout << "线程的句柄:" << hThread << endl;
   cout << "子线程的ID:" << threadId << endl; 
   cout << "主线程ID:" << GetCurrentThreadId() << endl;


   //关闭线程句柄,引用计数-1, 并没有结束线程
   //CloseHandle(hThread);//表示以后不再引用句柄 
   getchar();

   //挂起线程
   SuspendThread(hThread);

   getchar();

   //恢复线程执行
   ResumeThread(hThread);

   getchar();
    

   return 0; 
}


DWORD   WINAPI  ThreadFun(LPVOID lpThreadParameter)
{
   char *str = (char*)lpThreadParameter;

   while(TRUE)
   {  
      cout << "线程处理函数中:"<<str << endl;
      cout << "子线程ID: " << GetCurrentThreadId() << endl;

      Sleep(1000);//休眠1秒
   }

   return  0;
}

8.WaitForSingleobject

等待一个内核对象变为已通知状态

WaitForSingleObject function (synchapi.h) - Win32 apps | Microsoft Docs

DWORD WaitForSingleObject(
 HANDLE hHandle,
 DWORD  dwMilliseconds
);

该函数需要传递一个内核对象句柄,如果该内核对象处于未通知状态,则该函数导致线程进阻塞状态;如果该内核对象处于已通知状态则该函数立即返回 WAIT_OBJECT_0。第二个参数指明要等待的时间(毫秒),INFINITE表示无限等待,如果第二个参数为0,那么函数立即返回。如果等待超时,该函数返WAIT_TIMEOUT
如果该函数失败,返回 WAIT_FAILED

9. 终止线程

终止线程运行的最佳方法是让它的线程函数 return返回

除此之外,终止线程有两个函数

ExitThread() 避免使用

TerminateThread()必须避免

9.1 ExitThread()

ExitThread function (processthreadsapi.h) - Win32 apps | Microsoft Docs

void ExitThread(
 DWORD dwExitCode
);

可以让线程调用 ExitThread函数,以便强制线程终止运行:如果使用这两种方法退出线程,则不会执行线程函数的 return语句,所以就不会调用线程函数作用域内申请的类对象的析构函数,会造成內存泄露。

9.2 TerminateThread()

TerminateThread function (processthreadsapi.h) - Win32 apps | Microsoft Docs

BOOL TerminateThread(
 HANDLE hThread,
 DWORD  dwExitCode
);

Terminate thread能够撤消任何线程,hThread参数用于标识被终止运行的线程的句柄。dwExitcode参数就是线程终止的退出码。同时,线程的内核对象的使用计数也被递减。注意 Terminate thread函数是异步运行的函数当函数返回时,并不能保证线程被撤消。如果需要确切地知道该线程已经终止运行,使用 WaitForSingleobject或者类似的函数,

windows核心编程: 一个设计良好的应用程序决不会使用这个函数,因为被终止运行的线程收不到它被“杀死”的通知,导致线程不能正确地清除。

9.3 GetExitCodeThread获取线程结束码

GetExitCodeThread function (processthreadsapi.h) - Win32 apps | Microsoft Docs

BOOL GetExitCodeThread(
 HANDLE  hThread,
 LPDWORD lpExitCode
);

10. 示例代码2

情况1:

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

DWORD    WINAPI   ThreadFun( LPVOID   lpThreadParameter 	);

int  main()
{
   printf("主线程开头!\n");

   //创建线程
   HANDLE  hThread = CreateThread(NULL, 0, ThreadFun, NULL, 0, NULL);
    
   //无限等待,除非子线程运行结束
   WaitForSingleObject(hThread, INFINITE);

   printf("主线程结尾!\n");

   return 0;
}


DWORD    WINAPI   ThreadFun(LPVOID   lpThreadParameter)
{
   int  n = 0;
   while (++n<=6)
   {
   	 
   	printf("第%d次打印hello!\n", n );
   	Sleep(1000);

   	if (n == 3)
   	{
   		//退出线程,退出码为666,避免使用
   		ExitThread(666);
   	}

   } 
   return 0;

}

情况2:

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

DWORD    WINAPI   ThreadFun(LPVOID   lpThreadParameter);

int  main()
{
   printf("主线程开头!\n");

   //创建线程
   HANDLE  hThread = CreateThread(NULL, 0, ThreadFun, NULL, 0, NULL);

   DWORD  code;
   GetExitCodeThread(hThread, &code);
   if (code == STILL_ACTIVE)//如果线程没有结束,返回STILL_ACTIVE
   {
   	printf("子线程没有退出!\n");
   }

   //等待3秒,超时会返回
   DWORD  ret=WaitForSingleObject(hThread, 3000);
   if (ret == WAIT_TIMEOUT)
   {
   	printf("WaitForSingleObject等待子线程退出超时!\n");
   }

   //强制终止线程、避免使用
   TerminateThread(hThread, 888);

   //无限等待,除非子线程运行结束
   WaitForSingleObject(hThread, INFINITE);

   GetExitCodeThread(hThread, &code);
   printf("子线程退出码%d!\n",code); 

   printf("主线程结尾!\n");

   return 0;
}

DWORD    WINAPI   ThreadFun(LPVOID   lpThreadParameter)
{
   int  n = 0;
   while (++n <= 6)
   {

   	printf("第%d次打印hello!\n", n);
   	Sleep(1000);  

   }
   return 0;

}

情况3:

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

DWORD    WINAPI   ThreadFun(LPVOID   lpThreadParameter);

int  main()
{
   printf("主线程开始!\n");

   //创建线程
   HANDLE  hThread1 = CreateThread(NULL, 0, ThreadFun,(LPVOID) "A", 0, NULL);
   HANDLE  hThread2 = CreateThread(NULL, 0, ThreadFun, (LPVOID) "B", 0, NULL);
   HANDLE  hThread3 = CreateThread(NULL, 0, ThreadFun, (LPVOID) "C", 0, NULL);

   HANDLE  handleArr[] = { hThread1 ,hThread2 ,hThread3};

   //无限等待所有线程结束
   //DWORD  ret =  WaitForMultipleObjects(3,handleArr,true,INFINITE) ;
   // printf("ret== %d\n" ,ret== WAIT_OBJECT_0);

   //等待任意一个线程结束就返回数组索引
   //DWORD  ret = WaitForMultipleObjects(3, handleArr, false, INFINITE);
   //printf("ret== %d\n", ret);

   //设置等待超时时间1秒
   DWORD  ret = WaitForMultipleObjects(3, handleArr, false, 1000);
   printf("ret== %d\n", ret== WAIT_TIMEOUT);
      
   printf("主线程结尾!\n");

   return 0;
}

DWORD    WINAPI   ThreadFun(LPVOID   lpThreadParameter)
{

   char  * name = (char *)lpThreadParameter;
   
   if (strcmp(name, "A") == 0)
   {
   	Sleep(10000);
   }
   else if (strcmp(name, "C") == 0)
   {
   	Sleep(3000);
   }
   else
   {
   	Sleep(8000);
   }

   printf("%s线程结束!\n", name);
    
   return 0;
}

11. _beginthread

《windows核心编程》

CreateThread函数是用来创建线程的Windows函数。不过,如果你正在编写C/C++代码,决不应该调用 CreateThread。相反,应该使用 Visual c++运行期库函数_beginthread

在 Create thread ap创建的线程中使用sprintf,malloc,strcat等涉及CRT存储堆操作的CRT库函数是很危险的,容易造成线程的意外中止。而使用 _beginthread_beginthreadex创建的线程中可以安全的使用CRT函数,但是必须在线程结束的时候相应的调用 _endthread_endthreadex

如果你在线程函数中进行以下操作,你就应该使用 _beginthread_endthread

(1)使用 malloc()free(),或是newdelete

(2)使用 stdio.hio.h里面声明的任何函数

(3)使用浮点变量或浮点运算函数

(4)调用任何一个使用了静态缓冲区的 runtime函数比如 asctime()strtok()rand()

11.1 头文件

#include <process.h>

11.2 _beginthread创建线程

_beginthread、_beginthreadex | Microsoft Docs

uintptr_t _beginthread( // NATIVE CODE
  void( __cdecl *start_address )( void * ),
  unsigned stack_size,
  void *arglist
);
uintptr_t _beginthread( // MANAGED CODE
  void( __clrcall *start_address )( void * ),
  unsigned stack_size,
  void *arglist
);
uintptr_t _beginthreadex( // NATIVE CODE
  void *security,
  unsigned stack_size,
  unsigned ( __stdcall *start_address )( void * ),
  void *arglist,
  unsigned initflag,
  unsigned *thrdaddr
);
uintptr_t _beginthreadex( // MANAGED CODE
  void *security,
  unsigned stack_size,
  unsigned ( __clrcall *start_address )( void * ),
  void *arglist,
  unsigned initflag,
  unsigned *thrdaddr
);

11.3 _endthread终止线程

_endthread、_endthreadex | Microsoft Docs

void _endthread( void );
void _endthreadex(
  unsigned retval
);

_endthread:终止由 _beginthread创建的线程。对于使用 Libcmt.lib链接的可执行文件,不要调用Win32
API的 Exitthread(),它无法释放已分配的资源。而 _endthread回收线程资源然后调用 ExitThread_endthread自动关闭线程句柄。

12 示例代码3

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

void   ThreadFun(void*  param);

int main()
{
 printf("主线程开始!\n");

  //推荐使用C++运行期库函数_beginthread
 HANDLE  hThread=  (HANDLE)	_beginthread(ThreadFun, 0, "hello");

 WaitForSingleObject(hThread, INFINITE);

 printf("主线程结束!\n");
}

void   ThreadFun(void*  param)
{

   char *p = (char *)param;

   int  n = 0;
   while (++n <= 6)
   {
   	Sleep(1000);
   	printf("第%d次打印%s\n" , n,  p  );

   	//结束_beginthread创建的线程,别用ExitThread退出。
   	if (n == 3) _endthread();
   }

   printf("子线程结束!\n");
}
  • 3
    点赞
  • 8
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:猿与汪的秘密 设计师:我叫白小胖 返回首页
评论

打赏作者

超级大洋葱806

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值