总结有关创建线程的问题有四种方法:
1.C语言函数,调用_beginthread();
2.API函数,调用CreateThread();
3.MFC函数,调用AfxBeginThread();
4.C++11 的 std::thread
推荐使用MFC函数AfxBeginThread();
1._beginthreadunsigned long _beginthread( void(_cdecl *start_address)(void *), //声明为void (*start_address)(void *)形式 unsigned stack_size, //是线程堆栈大小,一般默认为0 void *arglist //向线程传递的参数,一般为结构体 ); unsigned long _beginthreadex( //推荐使用 void *security, //安全属性,NULL表示默认安全性 unsigned stack_size, //是线程堆栈大小,一般默认为0 unsigned(_stdcall *start_address)(void *), //声明为unsigned(*start_address)(void *)形式 void *argilist, //向线程传递的参数,一般为结构体 unsigned initflag, //新线程的初始状态,0表示立即执行,CREATE_SUSPEND表示创建后挂起。 unsigned *thrdaddr //该变量存放线程标识符,它是CreateThread函数中的线程ID。 ); //创建成功条件下的将线程句柄转化为unsigned long型返回,创建失败条件下返回0 //释放线程空间、释放线程TLS空间、调用ExiteThread结束线程。 void _endthread(void); // retval:设定的线程结束码,与ExiteThread函数的参数功能一样, //其实这个函数释放线程TLS空间,再调用ExiteThread函数,但没有释放线程空间。 void _endthreadex(unsigned retval);
// 使用beginThread创建一个线程 #include2.CreateThread//头文件 #include #include 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, first,nullptr,0,&d1); CloseHandle(handle); Sleep(1000); std::cout << "handle = " << handle << std::endl; std::cout << "threadid = " << d1 << std::endl; return 0; }
//如果函数调用成功,则返回新线程的句柄,调用WaitForSingleObject函数等待所创建线程的运行结束
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,//指向SECURITY_ATTRIBUTES的指针,用于定义新线程的安全属性,一般设置成NULL;
DWORD dwStackSize,//分配以字节数表示的线程堆栈的大小,默认值是0;
LPTHREAD_START_ROUTINE lpStartAddress,//指向一个线程函数地址。函数名称没有限制,但是必须以下列形式声明:DWORD WINAPI ThreadProc (PVOID pParam) ;
LPVOID lpParameter,//传递给线程函数的参数;
DWORD dwCreationFlags,//表示创建线程的运行状态,其中CREATE_SUSPEND表示挂起当前创建的线程,而0表示立即执行当前创建的进程;
LPDWORD lpThreadID//返回新创建的线程的ID编号;
);
DWORD WaitForSingleObject(
HANDLE hHandle,//指定对象或时间的句柄;
DWORD dwMilliseconds//等待时间,以毫秒为单位,当超过等待时间时,此函数返回。如果参数设置为0,则该函数立即返回;如果设置成INFINITE,则该函数直到有信号才返回。
);
ResumeThread 恢复线程的运行;
SuspendThread 挂起线程.
GetCurrentThread 获取一个伪句柄
DuplicateHandle 复制一个句柄
GetCurrentThreadId、MainThreadID、MainInstance 获取当前线程的 ID
GetExitCodeThread 获取退出码,如果线程没有退出, 是一个常量 STILL_ACTIVE (259);
//Threadbase.cpp
#include "StdAfx.h"
#include "Threadbase.h"
CThreadbase::CThreadbase(void)
{
m_hThread = CreateThread(NULL,0,ThreadProc,this,CREATE_SUSPENDED,&m_dwThreadID);
}
CThreadbase::~CThreadbase(void)
{
CloseHandle(m_hThread);
}
DWORD WINAPI CThreadbase::ThreadProc (PVOID pParam)
{
if (NULL!=pParam)
{
((CThreadbase*)pParam)->Run();
}
return 0;
}
void CThreadbase::Start()
{
ResumeThread(m_hThread);
}
3.AfxBeginThread
//返回值:一个指向新线程的线程对象。
CWinThread* AfxBeginThread(
AFX_THREADPROC pfnThreadProc , //线程的入口函数,声明一定要如下:UINT MyThreadFunction( LPVOID pParam );
LPVOID pParam , //传递入线程的参数,注意它的类型为:LPVOID,所以我们可以传递一个结构体入线程。
int nPriority = THREAD_PRIORITY_NORMAL , //线程的优先级,一般设置为 0。让它和主线程具有共同的优先级。
UINT nStackSize = 0 , //指定新创建的线程的栈的大小。如果为 0,新创建的线程具有和主线程一样的大小的栈。
DWORD dwCreateFlags = 0, //指定创建线程以后,线程有怎么样的标志。可以指定两个值:<1>CREATE_SUSPENDED:线程创建以后,会处于挂起状态,直到调用ResumeThread;<2>0:创建线程后就开始运行。
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL//指向一个 SECURITY_ATTRIBUTES 的结构体,用它来标志新创建线程的安全性。如果为 NULL,那么新创建的线程就具有和主线程一样的安全性
);
1).线程的等待与唤醒
(1)让线程等待(暂时挂起):
MyThread->SuspendThread();
(2)唤醒暂停的线程:
MyThread->ResumeThread();
2).查看线程状态:
DWORD code; GetExitCodeThread(MyThread->m_hThread , &code); if(code==STILL_ACTIVE) {//线程仍在执行} else {//线程停止执行}
3).结束线程
TerminateThread(MyThread->m_hThread , 0);
4.std::thread#include#include #include using namespace std; void thread_one() { puts("hello"); } void thread_two(int num, string& str) { cout << "num:" << num << ",name:" << str << endl; } int main(int argc, char* argv[]) { thread tt(thread_one); tt.join();//等待子线程执行完成之后,主线程才继续执行,此时主线程会释放掉执行完成后的子线程的资源。 string str = "luckin"; thread yy(thread_two, 88, ref(str)); //这里要注意是以引用的方式调用参数 yy.detach();//主线程不想等待子线程,使用detach()将子线程从主线程中分离出来,这样主线程就对子线程没有控制权了,子线程执行完成后会自己释放掉资源。 system("pause"); return 0; }
get_id():获取线程的ID,它将返回一个类型为std::thread::id的对象。
joinable():检查线程是否可被join
detach():将当前线程对象所代表的执行实例与此线程对象分离,使得线程可以单独执行。
swap():交换两个线程对象所代表的底层句柄,参数是两个线程对象;
std::this_thread::getid():获取当前线程的ID;
std::this_thread::yield():当前线程放弃执行,操作系统调度另一线程继续执行;
sleep_until():线程休眠至某个指定的时刻,才被重新唤醒;
sleep_for(): 线程休眠某个指定的时间片,才被重新唤醒;
在任意一个时间点上,线程是可结合joinable或者可分离detached的。
一个可结合线程是可以被其它线程回收资源和杀死结束的,而对于detached状态的线程,其资源不能被其它线程回收和杀死,只能等待线程结束才能由系统自动释放。
由默认构造函数创建的线程(默认构造函数,创建一个空的thread执行对象)是不能被join的;
另外,若某个线程已执行完任务,但是没有被join的话,该线程依然会被认为是一个活动的执行线程,因此是可以被join的。



