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

_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 <stdio.h>
#include <Windows.h>
#include <process.h>

/* 线程函数声明 */
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 <stdio.h>
#include <Windows.h>
#include <process.h>

/* 线程函数声明 */
//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);
	}
}

输出结果
在这里插入图片描述

  • 6
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值