总结有关创建线程的问题有四种方法:
1.C语言函数,调用_beginthread();
2.API函数,调用CreateThread();
3.MFC函数,调用AfxBeginThread();
4.C++11 的 std::thread
推荐使用MFC函数AfxBeginThread();
1._beginthread
unsigned long _beginthread(void(_cdecl *start_address)(void *), //声明为void (*start_address)(void *)形式unsigned stack_size, //是线程堆栈大小,一般默认为0void *arglist //向线程传递的参数,一般为结构体
);unsigned long _beginthreadex( //推荐使用void *security, //安全属性,NULL表示默认安全性unsigned stack_size, //是线程堆栈大小,一般默认为0unsigned(_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创建一个线程
#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, first,nullptr,0,&d1);CloseHandle(handle);Sleep(1000);std::cout << "handle = " << handle << std::endl;std::cout << "threadid = " << d1 << std::endl;return 0;
}
2.CreateThread
//如果函数调用成功,则返回新线程的句柄,调用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 <iostream>
#include <thread>
#include <string>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的。