创建线程——_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);	
    

    可以显示的调用这两个函数来结束线程。系统从线程启动函数返回时,也会自动调用相应的结束 线程函数,收回分配给线程的资源。

区别

两组函数都是用来创建和结束线程的。这两对函数的不同点如下:

  1. 从形式上开,_beginthreadex()更像CreateThread()。_beginthreadex()比_beginthread()多3个参数:intiflag,security和threadaddr。
  2. 两种创建方式的线程函数不同。_beginthreadex()的线程函数必须调用_stdcall调用方式,而且必须返回一个unsigned int型的退出码。
  3. _beginthreadex()在创建线程失败时返回0,而_beginthread()在创建线程失败时返回-1。这一点是在检查返回结果是必须注意的。
  4. 如果是调用_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;
}

枪战模式
创建线程——_beginthread 和 _beginthreadex【方法2】

实例二:

#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;
}

创建线程——_beginthread 和 _beginthreadex【方法2】

总结:
https://blog.****.net/youshijian99/article/details/79679783
https://blog.****.net/xuanyin235/article/details/77693275