C++ 使用_beginthreadex创建线程、线程句柄(等待线程关闭)、线程id的作用(发送线程消息)

_beginthreadex

c语言库 process.h 中的函数, 用来创建一个线程

unsigned long _beginthreadex(

  

    void *security,    // 安全属性, 为NULL时表示默认安全性

 

    unsigned stack_size,    // 线程的堆栈大小, 一般默认为0

 

    unsigned(_stdcall *start_address)(void *),    // 所要启动的线程函数

 

    void *argilist, // 线程函数的参数, 是一个void*类型, 传递多个参数时用结构体

 

    unsigned initflag,    // 新线程的初始状态,0表示立即执行,CREATE_SUSPENDED

表示创建之后挂起

    unsigned *threaddr    // 用来接收线程ID

 

);


返回值 : // 成功返回新线程句柄, 失败返回0

使用_beginthreadex创建线程 

// 使用beginThread创建一个线程
#include <process.h>
#include <windows.h>
#include <iostream>
unsigned int __stdcall first(void*)
{
	std::cout << "this is first thread!" << std::endl;
	return 0;
}
int main()
{
	unsigned int d1;
	HANDLE handle;
	handle = (HANDLE)_beginthreadex(nullptr,0, (unsigned int(__stdcall *)(void *))first,nullptr,0,&d1);
    CloseHandle(handle);
	Sleep(1000);
	std::cout << "handle = " << handle << std::endl;
	std::cout << "threadid = " << d1 << std::endl;
	return 0;

}

运行结果:

使用类的静态成员函数创建线程

// 使用beginThread创建一个线程
#include <process.h>
#include <windows.h>
#include <iostream>
 
struct MYdataValue
{
	MYdataValue(int d1,double d2):
		a(d1),
		b(d2)
	{}
	int a;
	double b;
};
class CThreadCls
{
public:
	static unsigned int __stdcall first(void* p);
};
 
unsigned int __stdcall CThreadCls::first(void* p)
{
	MYdataValue* pThis = (MYdataValue*)p;
	std::cout << "this is CThreadCls::first thread! num = "<<pThis->a<<"double = "<<pThis->b << std::endl;
	delete pThis;
	return 0;
}
 
int main()
{
	unsigned int d1;
	HANDLE handle;
	MYdataValue*  pData = new MYdataValue(1,3.22);
	handle = (HANDLE)_beginthreadex(nullptr,0, (unsigned int(__stdcall *)(void *))CThreadCls::first, pData,0,&d1);
    CloseHandle(handle);
	Sleep(1000);
	std::cout << "handle = " << handle << std::endl;
	std::cout << "threadid = " << d1 << std::endl;
	return 0;
}

如果是有界面的进程,则在等待子线程的过程中,我们需要获取消息队列,否则界面会卡死。

2.线程句柄的作用
今天温习很久前写的代码,发现自己写的这么一句代码,

m_hTheard = CreateThread(NULL,0,RegNotifyProc,LPVOID(this),0,NULL);
CloseHandle(m_hTheard);

突然给糊涂了,刚创建的线程,为什么有close了,还是当初入门不踏实,没有细想,现在反过来都记不得了,通过查资料,解决了我的疑惑。

1,线程和线程句柄(Handle)不同,线程是一个程序的工作流程,线程句柄是一个内核对象。线程的生命周期就是线程函数从开始执行到线程结束,线程句柄一旦CreateThread返回,如果你不用其它操作线程或者等待线程等操作比如waitforsingleobject,就可以CloseHandle。

(ps:对于线程来讲,如果线程在运行状态则为无信号状态,在退出后为有信号状态。所以我们可以使用 WaitForSingleObject 来等待线程退出)例子:等待线程退出
 

// 使用beginThread创建一个线程,等待线程退出
#include <process.h>
#include <windows.h>
#include <iostream>
 
struct MYdataValue
{
	MYdataValue(int d1,double d2):
		a(d1),
		b(d2)
	{}
	int a;
	double b;
};
class CThreadCls
{
public:
	static unsigned int __stdcall first(void* p);
};
 
unsigned int __stdcall CThreadCls::first(void* p)
{
	MYdataValue* pThis = (MYdataValue*)p;
	std::cout << "this is CThreadCls::first thread! num = "<<pThis->a<<"double = "<<pThis->b << std::endl;
	delete pThis;
	Sleep(5000);
	return 0;
}
 
int main()
{
	unsigned int d1;
	HANDLE handle;
	MYdataValue*  pData = new MYdataValue(1,3.22);
	handle = (HANDLE)_beginthreadex(nullptr,0, (unsigned int(__stdcall *)(void *))CThreadCls::first, pData,0,&d1);
	if (WAIT_OBJECT_0 == WaitForSingleObject(handle, INFINITE))//等待子线程结束
	{
		std::cout << "thread excute end!" << std::endl;
	}
	std::cout << "handle = " << handle << std::endl;
	std::cout << "threadid = " << d1 << std::endl;
	CloseHandle(handle);
	return 0;

}

例子:等待线程退出,并在等待过程中分发消息,使用MsgWaitForMultipleObjects,这个函数在收到消息时也会返回,而不是傻傻的等着:

HANDLE hThreadbar = (HANDLE)_beginthreadex(NULL, 0, (unsigned int(__stdcall *)(void *))MStartThread, this, 0, NULL);
            DWORD dwRet;
            DoEvent();
            do
            {
                dwRet = ::MsgWaitForMultipleObjects(1, &hThreadbar, FALSE, INFINITE, QS_ALLINPUT);
                if (dwRet != WAIT_OBJECT_0)
                {
                    DoEvent();
                }
            } while ((dwRet != WAIT_OBJECT_0) && (dwRet != WAIT_FAILED));
void CSettingDlg::DoEvent()
{
    MSG msg;
    if(::PeekMessage(&msg,NULL,0,0,PM_REMOVE))  //取消息,检索应用程序的消息队列,PM_REMOVE取过之后从消息队列中移除
    {
        //发消息
        ::TranslateMessage(&msg); 
        ::DispatchMessage(&msg);
    }

}

2,CreateThread以后需要对这个线程做一些操作,比如改变优先级,被其他线程等待,强制TermateThread等,就要保存这个句柄,使用完了再操作CloseHandle。

3、CloseHandle只是关闭了一个线程句柄对象,表示我不再使用该句柄,即不对这个句柄对应的线程做任何干预了,和结束线程没有一点关系。若在线程执行完之后,没有调用CloseHandle,在进程执行期间,将会造成内核对象的泄露,相当于句柄泄露,但不同于内存泄露,这势必会对系统的效率带来一定程度上的负面影响。但当进程结束退出后,系统会自动清理这些资源。

4、关闭一个内核对象。其中包括文件、文件映射、进程、线程、安全和同步对象等。在CreateThread成功之后会返回一个hThread的handle,且内核对象的计数加1,CloseHandle之后,引用计数减1,当变为0时,系统删除内核对象。

做一些总结,以作知识积累。

3.线程ID的作用
PostThreadMessage发送线程消息

PostThreadMessage是一个Windows API函数。其功能是将一个队列消息放入(寄送)到指定线程的消息队列里,不等待线程处理消息就返回。

BOOLPostThreadMessage(

DWORDidThread,

UINTMsg,

WPARAMwParam,

LPARAMIParam

);


参数
编辑

idThread

其消息将被寄送的线程的线程标识符。如果线程没有消息队列,此函数将失败。当线程第一次调用一个Win 32 USER或GDI函数时,系统创建线程的消息队列。要得到更多的信息,参见备注。

Msg

指定将被寄送的消息的类型。

wParam

指定附加的消息特定信息。

IParam

指定附加的消息特定信息。


返回值
编辑

如果函数调用成功,返回非零值。如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。如果idThread不是一个有效的线程标识符或由idThread确定的线程没有消息队列,GetLastError返回ERROR_INVALID_THREAD_ID。


备注
编辑

消息将寄送到的线程必须创建消息队列,否则调用PostThreadMessage会失败。用下列方法之一来处理这种情况:

调用PostThreadMessage。如果失败,调用Sleep,再调用PostThreadMessage,反复执行,直到PostThreadMessage成功。

创建一个事件对象,再创建线程。在调用PostThreadMessage之前,用函数WaitForSingleObject来等待事件被设置为被告知状态。消息将寄送到的线程调用PeekMessage(&msg,NULL,WM_USER,WM_USER,PM_NOREMOVE)来强制系统创建消息队列。设置事件,表示线程已准备好接收寄送的消息。

消息将寄送到的线程通过调用GetMessage或PeekMessage来取得消息。返回的MSG结构中的hwnd成员为NULL。

每一个消息队列将队列内的消息限制在10,000个。这个限制应该已经足够的大。如果一个程序超过这个限制,它应当被重新设计以避免占用如此多的系统资源。要修改消息个数的限制,应当修改注册表中对应的项。

线程消息示例:

报错:"Severity Code Description Project File Line
Error (active) argument of type “void (*)(A &a)” is incompatible with parameter of type “_beginthreadex_proc_type”
"求助!!!!!!

A::run1前加上(unsigned int (__stdcall *)(void *))

 #include<iostream>
#include<Windows.h>
#include <process.h>  
using namespace std;

class A {
public:
    int n;
    A(int n) {
        this->n = n;
    }
    void static run1(A &a);
    void static run2(A &a);
    void static run(A &a);
};
void A::run1(A &a) {
    for (int i = 0; i < a.n; ++ i)
        cout << "run1" << endl;
}
void A::run2(A &a) {
    for (int i = 0; i < a.n; ++i)
        cout << "run2" << endl;
}
void A::run(A &a) {
    A * p = &a;
    HANDLE h1, h2;
    h1 = (HANDLE)_beginthreadex(NULL, 0,(unsigned int (__stdcall *)(void *))A::run1, p, 0, 0);
    h2 = (HANDLE)_beginthreadex(NULL, 0, (unsigned int (__stdcall *)(void *))A::run2, p, 0, 0);
}
int main()
{
    A a(3);
    a.run(a);
    return 0;
}

https://blog.csdn.net/qq_24127015/article/details/85157890
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值