创建线程——_beginthread 和 _beginthreadex【方法2】
并不是Windows标准API,创建线程函数,该函底层调用CreateThread。
头文件
#include <process.h>
函数原型
unsigned long _beginthread(
void(_cdecl *start_address)(void *), //声明为void (*start_address)(void *)形式
unsigned stack_size, //是线程堆栈大小,一般默认为0
void *arglist //向线程传递的参数,一般为结构体
);
typedef unsigned int uintptr_t;
typedef unsigned (__stdcall* _beginthreadex_proc_type)(void*);
uintptr_t _beginthreadex(
void* _Security, //线程安全属性
unsigned _StackSize, //线程堆栈大小
_beginthreadex_proc_type _StartAddress, //线程函数地址
void* _ArgList, //传递给线程函数的地址
unsigned _InitFlag, //指定线程是否立即启动
unsigned* _ThrdAddr //存储线程id号
);
安全属性
SECURITY_ATTRIBUTES结构包含一个对象的安全描述符,并指定检索到指定这个结构的句柄是否是可继承的。这个结构为很多函数创建对象时提供安全性设置。如:CreateFile,CreatePipe,CreateProcess,RegCreateKeyEx,RegSaveKeyEx。
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength; //结构体的大小,可用SIZEOF取得
LPVOID lpSecurityDescriptor; //安全描述符
BOOL bInheritHandle; //安全描述的对象能否被新创建的进程继承
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
线程终止
线程函数退出。
线程使用的堆栈被释放。
dwExitCode设置为线程函数的返回值。
递减内核中的code值,让内核的引用计数减一。
-
结束线程调用,终止自己
VOID WINAPI ExitThread( __in DWORD dwExitCode // 线程结束时的退出码 );
-
由当前线程终止其他线程
BOOL WINAPI TerminateThread( __in_out HANDLE hThread, // 终止的线程句柄 __in DWORD dwExitCode // 退出码 );
-
释放线程空间、释放线程TLS空间、调用ExiteThread结束线程
void _endthread(void); // retval:设定的线程结束码,与ExiteThread函数的参数功能一样, //其实这个函数释放线程TLS空间,再调用ExiteThread函数,但没有释放线程空间。 void _endthreadex(unsigned retval);
可以显示的调用这两个函数来结束线程。系统从线程启动函数返回时,也会自动调用相应的结束 线程函数,收回分配给线程的资源。
区别
两组函数都是用来创建和结束线程的。这两对函数的不同点如下:
- 从形式上开,_beginthreadex()更像CreateThread()。_beginthreadex()比_beginthread()多3个参数:intiflag,security和threadaddr。
- 两种创建方式的线程函数不同。_beginthreadex()的线程函数必须调用_stdcall调用方式,而且必须返回一个unsigned int型的退出码。
- _beginthreadex()在创建线程失败时返回0,而_beginthread()在创建线程失败时返回-1。这一点是在检查返回结果是必须注意的。
- 如果是调用_beginthread()创建线程,并相应地调用_endthread()结束线程时,系统自动关闭线程句柄;而调用_beginthreadx()创建线程,并相应地调用_endthreadx()结束线程时,系统不能自动关闭线程句柄。因此调用_beginthreadx()创建线程还需程序员自己关闭线程句柄,以清除线程的地址空间。
原文:https://blog.****.net/xuanyin235/article/details/77693275
实例
实例一:
#include <iostream>
#include <windows.h>
#include <process.h>
using namespace std;
unsigned int WINAPI ThreadProFunc(void *pParam);
int main(int argc, char **argv)
{
HANDLE hThread;
unsigned int threadId;
hThread = (HANDLE)_beginthreadex(NULL, NULL, ThreadProFunc, NULL, 0, &threadId);
for (int i = 0; i < 100; i++) {
cout << "nihao" << endl;
}
CloseHandle(hThread); //关闭线程句柄
system("pause");
return 0;
}
unsigned int WINAPI ThreadProFunc(void *pParam)
{
for (int i = 0; i < 100; i++) {
cout<<"hello\n";
}
return 0;
}
枪战模式
实例二:
#include <Windows.h>
#include <process.h>
#include <iostream>
using namespace std;
typedef struct _STRUCT_DATA_
{
int id; //用于标识出票id
int tickets;
}_DATA, *_pDATA;
//CRITICAL_SECTION g_cs;
unsigned __stdcall Fun1(LPVOID lpParam);
unsigned __stdcall Fun2(LPVOID lpParam);
void main()
{
HANDLE hThread[2] = { NULL,NULL };
unsigned threadid[2] = { 0 };
_DATA stru_data;
stru_data.id = 0;
stru_data.tickets = 200;
hThread[0] = (HANDLE)_beginthreadex(NULL, 0, Fun1, &stru_data, 0, &threadid[0]);
hThread[1] = (HANDLE)_beginthreadex(NULL, 0, Fun2, &stru_data, 0, &threadid[1]);
//InitializeCriticalSection(&g_cs);
Sleep(4000);
//LeaveCriticalSection(&g_cs);
}
unsigned __stdcall Fun1(LPVOID lpParam)
{
_pDATA data = (_pDATA)lpParam;
while (TRUE)
{
//EnterCriticalSection(&g_cs);
if (data->tickets > 0)
{
Sleep(1);
cout << "fun1: " << data->id++ ;
cout << " *** thread 1 :sell ticket: " << data->tickets-- << endl;
//LeaveCriticalSection(&g_cs);
}
else
{
//LeaveCriticalSection(&g_cs);
break;
}
}
return 0;
}
unsigned __stdcall Fun2(LPVOID lpParam)
{
_pDATA data = (_pDATA)lpParam;
while (TRUE)
{
//EnterCriticalSection(&g_cs);
if (data->tickets > 0)
{
Sleep(1);
cout << "fun2: " << data->id++ ;
cout << " === thread 2:sell ticket: " << data->tickets-- << endl;
// LeaveCriticalSection(&g_cs);
}
else
{
//LeaveCriticalSection(&g_cs);
break;
}
}
return 0;
}
总结:
https://blog.****.net/youshijian99/article/details/79679783
https://blog.****.net/xuanyin235/article/details/77693275