【C语言】Windows下的多线程编程

【C语言】Windows下的多线程编程,第1张

_beginthread_beginthreadex是Windows下创建线程的函数。


结束线程函数_endthread_endthreadex

主线程结束了,子线程也会结束。

_beginthread函数原型
/** \brief 	创建一个线程
 *
 * \param   start_address 新线程的起始地址 ,指向新线程调用的函数的起始地址
 * \param   stack_size 新线程的堆栈大小,可以为0
 * \param   arglist 传递给线程的参数列表,无参数时为NULL,多参数的时候可以传入结构体
 * \return  成功,函数将会返回一个新线程的句柄
 *			失败_beginthread将返回-1
 *			如 th1 = (HANDLE)_beginthread(Thread1, 0, NULL);
 *
 */
uintptr_t _beginthread(void(*start_address)(void*),
	unsigned stack_size,
	void* arglist);

uintptr_t的类型为unsigned long long

typedef unsigned __int64  uintptr_t;
_beginthreadex函数原型
/** \brief 	创建一个线程
 *
 * \param   security 安全属性, 为 NULL时表示默认安全性
 * \param   stack_size 新线程的堆栈大小,一般默认为0
 * \param   start_address 指定线程函数,也就是线程调用执行的函数地址
 * \param   arglist 传递给线程的参数列表,无参数时为 NULL,多参数的时候可以传入结构体
 * \param   initflag 新线程的初始状态,0表示立即执行,CREATE_SUSPENDED表示创建之后挂起
 * \param   threaddr 指向接收线程标识符的 32 位变量。

如果是 NULL ,则不使用 * \return 成功,函数将会返回一个新线程的句柄 * 发生错误时, _beginthreadex 返回 0 并设置 errno 和 _doserrno * */ uintptr_t _beginthreadex(void* security, unsigned stack_size, unsigned(_stdcall* start_address)(void*), void* argilist, unsigned initflag, unsigned* threaddr);

_endthread函数原型
/** \brief 	终止线程
 *
 * \param   无
 * \return  无
 *
 */
void _endthread(void);

注意:_endthread 会自动关闭线程句柄。

(该行为与 Win32 ExitThread API 不同。

) 因此,当你使用 _beginthread_endthread 时,不要通过调用 Win32 CloseHandle API 来显式关闭线程句柄。

_endthreadex函数原型
/** \brief 	终止线程
 *
 * \param   retval 线程退出代码
 * \return  无
 *
 */
void _endthreadex(unsigned retval);

注意: _endthreadex 不会关闭线程句柄。

因此,当你使用 _beginthreadex_endthreadex时,必须通过调用 Win32 CloseHandle API 来关闭线程句柄。

示例1
#include 
#include 
#include 

/* 线程函数声明 */
void Thread1(void*);
void Thread2(void*);
//unsigned int __stdcall Thread1ex(void*);
//unsigned int __stdcall Thread2ex(void*);

/* 线程句柄 */
HANDLE h1, h2;

/* 线程共享内存 */
volatile int i = 0;

/* 主线程 */
int main()
{
	/* 创建线程 */
	h1 = (HANDLE)_beginthread(Thread1, 0, NULL);//线程1
	h2 = (HANDLE)_beginthread(Thread2, 0, NULL);//线程2
	//h1 = (HANDLE)_beginthreadex(NULL, 0, Thread1ex, NULL, 0, NULL);
	//h2 = (HANDLE)_beginthreadex(NULL, 0, Thread2ex, NULL, 0, NULL);

	WaitForSingleObject(h1, INFINITE);//等待线程1结束
	WaitForSingleObject(h2, INFINITE);//等待线程2结束
	//system("pause");

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


/* 线程1 */
void Thread1(void* arg)
{
	while (1)
	{
		printf("Thread1\n");
		Sleep(100);
	}
}


/* 线程2 */
void Thread2(void* arg)
{
	while (1)
	{
		printf("Thread2\n");
		Sleep(100);
	}
}


///* 线程1 */
//unsigned int __stdcall Thread1ex(void* arg)
//{
//	while (1)
//	{
//		printf("Thread1\n");
//		Sleep(100);
//	}
//}
//
//
///* 线程2*/
//unsigned int __stdcall Thread2ex(void* arg)
//{
//	while (1)
//	{
//		printf("Thread2\n");
//		Sleep(100);
//	}
//}

输出结果

WaitForSingleObject
/** \brief 	等待函数 – 使线程进入等待状态,直到指定的内核对象被触发。

* * \param hHandle 要等待的内核对象 * \param dwMilliseconds 最长等待的时间,以毫秒为单位;传入0就立即返回,传入INFINITE表示无限等待 * \return 在指定的时间内对象被触发,函数返回WAIT_OBJECT_0 * 超过最长等待时间对象仍未被触发返回WAIT_TIMEOUT。

传入参数有错误将返回WAIT_FAILED * */ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);

WaitForSingleObject函数用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。

对应的还有一个函数

WaitForMultipleObjects
/** \brief 	等待函数 – 使线程进入等待状态,直到指定的内核对象被触发。

* * \param nCount lpHandles指向的数组中的对象句柄数。

对象句柄的最大数量为MAXIMUM_WAIT_OBJECTS。

此参数不能为零 * \param lpHandles 一组对象句柄。

该数组可以包含不同类型对象的句柄。

它可能不包含同一句柄的多个副本 * 如果其中一个句柄在等待仍处于暂挂状态时关闭,则该函数的行为未定义 * \param bWaitAll 如果此参数为TRUE,则在lpHandles数组中的所有对象的状态发出信号时,该函数返回。

如果为FALSE,则当任何一个对象的状态设置为信号时,该函数返回 在后一种情况下,返回值表示其状态导致函数返回的对象。

* \param dwMilliseconds 最长等待的时间,以毫秒为单位;传入0就立即返回,传入INFINITE表示无限等待 * \return 返回WAIT_OBJECT_0则返回值表明所有指定对象的状态信号 * 超过最长等待时间对象仍未被触发返回WAIT_TIMEOUT。

传入参数有错误将返回WAIT_FAILED * */ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds );

示例2

线程1与线程2通过共享内存来通讯。

#include 
#include 
#include 

/* 线程函数声明 */
//void Thread1(void*);
//void Thread2(void*);
unsigned int __stdcall Thread1ex(void*);
unsigned int __stdcall Thread2ex(void*);

/* 线程句柄 */
HANDLE h1, h2;

/* 线程共享内存 */
volatile int i = 0;

/* 主线程 */
int main()
{
	/* 创建线程 */
	//h1 = (HANDLE)_beginthread(Thread1, 0, NULL);//线程1
	//h2 = (HANDLE)_beginthread(Thread2, 0, NULL);//线程2
	h1 = (HANDLE)_beginthreadex(NULL, 0, Thread1ex, NULL, 0, NULL);
	h2 = (HANDLE)_beginthreadex(NULL, 0, Thread2ex, NULL, 0, NULL);

	while (1)
	{
		printf("Main Thread\n");
		Sleep(100);
	}
	system("pause");

	return 0;
}


///* 线程1 */
//void Thread1(void* arg)
//{
//	while (1)
//	{
//		printf("Thread1\n");
//		Sleep(100);
//	}
//}
//
//
///* 线程2 */
//void Thread2(void* arg)
//{
//	while (1)
//	{
//		printf("Thread2\n");
//		Sleep(100);
//	}
//}


/* 线程1 */
unsigned int __stdcall Thread1ex(void* arg)
{
	while (1)
	{
		i++;
		Sleep(100);
	}
}


/* 线程2*/
unsigned int __stdcall Thread2ex(void* arg)
{
	while (1)
	{
		printf("i = %d\n", i);
		Sleep(100);
	}
}

输出结果

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/662196.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-18
下一篇 2022-04-18

发表评论

登录后才能评论

评论列表(0条)

保存