最近参加面试,被面试官问到了Windows线程开发相关的问题,完全回答不上来。百度一下很多关于多线程的说明,在此我整理下便于自己以后查找。
主要问题有
1. 线程的创建
2.线程的销毁
3.线程同步,通信
第一节 关于线程的创建
可以通过以下几种方法创建一个线程:
1、CreateThread
2、_beginthread
3、_beginthreadex
4、AfxBeginThread
第一种 windows API
HANDLE CreateThread(PL_SECURITY_ATTIBUTE plsa, DWOD cbStack, LP_THREAD_START_ROUTINE lpst, LPVOID lpvThreadParam, DWOD fdwCreate, LPWORD lpIDThread);
线程函数定义 DWOD ThreadFunc(LPVOID param);
第二中和第三种
引用头文件:
#include <process.h>
函数原型:
uintptr_t _beginthread( void( *start_address )( void * ),
unsigned stack_size,
void *arglist );
参数:
start_address:新线程的起始地址 ,指向新线程调用的函数的起始地址
stack_size:新线程的堆栈大小,可以为0
arglist: 传递给线程的参数列表,无参数是为NULL
返回值:
假如成功,函数将返回一个处理信息对这个新创建的线程。如果失败_beginthread将返回-1。
unsigned long _beginthreadx(void* security,
unsigned stack_size,
unsigned (__stdcall *start_addr)(void*),
void* arglist,
unsigned initFlag,
unsigned* threadAddr);
参数:可参考CreateThread函数的参数
返回值:
与_beginthread()不同的是:_beginthread返回-1表示失败, 而_beginthreadex()返回0表示失败!
第四种,MFC中使用
在MFC中,用户界面线程和工作者线程都是由AfxBeginThread创建的,MFC提供了两个重载版的AfxBeginThread,一个用于用户界面线程,另一个用于工作者线程,分别有如下的原型和过程:
原型一(用户界面线程):
CWinThread* AFXAPI AfxBeginThread( CRuntimeClass* pThreadClass,
int nPriority,
UINT nStackSize,
DWORD dwCreateFlags,
LPSECURITY_ATTRIBUTES lpSecurityAttrs)
参数:
pThreadClass:从CWinThread派生的RUNTIME_CLASS类;
nPriority:指定线程优先级,如果为0,则与创建该线程的线程相同;
nStackSize:指定线程的堆栈大小,如果为0,则与创建该线程的线程相同;
dwCreateFlags:一个创建标识,如果是CREATE_SUSPENDED,则在悬挂状态创建线程,在线程创建后线程挂起,否则线程在创建后开始线程的执行。
lpSecurityAttrs:表示线程的安全属性,NT下有用。
原型二(工作线程)
CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc,
LPVOID lParam,
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);//用于创建工作者线程
参数:
pfnThreadProc : 线程的入口函数,声明一定要如下: UINT MyThreadFunction(LPVOID pParam),不能设置为NULL;
pParam : 传递入线程的参数,注意它的类型为:LPVOID,所以我们可以传递一个结构体入线程.
nPriority : 线程的优先级,一般设置为 0 .让它和主线程具有共同的优先级.
nStackSize : 指定新创建的线程的栈的大小.如果为 0,新创建的线程具有和主线程一样的大小的栈
dwCreateFlags : 指定创建线程以后,线程有怎么样的标志.可以指定两个值:
--------------------------------------------------------------------------------------
CREATE_SUSPENDED : 线程创建以后,会处于挂起状态,直到调用:ResumeThread
0 : 创建线程后就开始运行.
--------------------------------------------------------------------------------------
lpSecurityAttrs : 指向一个 SECURITY_ATTRIBUTES 的结构体,用它来标志新创建线程的安全性.如果为 NULL,
返回值:
一个指向新线程的线程对象的指针
以上几种创建线程的区别
其实windows只提供了一个创建线程的方法,就是CreateThread,后面三个函数都是由CreateThread间接得到。
1、_beginthread和_beginthreadex的区别
首先我们看看这两个函数都干了什么:
uintptr_r __cdecl _beginthreadex(...)
{
//为即将创建的线程分配一个数据结构_ptiddata ptd(per-thread data)
//初始化这个数据结构,其中ptd->_thandle = (uintptr_t)(-1)
//如果初始化失败,返回(uintptr_t)(0) [_beginthread返回-1]
//用传进来的参数,调用CreateThread
//如果创建成功返回CreateThread返回的代码
//如果创建失败则释放ptd,并返回(uintptr_t)(0) [_beginthread返回-1,而CreateThread失败返回0,非-1]
}
然后再看看这两个函数有什么不同
(1)参数列表不同, ex版本的参数和CreateThread差不多:
(2)二者在初始化ptd失败时返回的值不同
(3)_beginthread的参数缺少安全描述符. 而且它是创建线程的时候先以挂起状态创建 (CreateThread会填充ptd->_thandle和ptd->_tid) 然后再ResumeThread。_beginthread是根据传进来的参数创建线程
(4)失败返回值不同,ex版本的与Windows API CreateThread返回值是一直的,这也是提倡使用后者的原因之一
2、CreateThread()、_beginthreadex()及、AfxBeginThread()
CreateThread时Windows API接口函数,_beginthreadex函数是C/C++运行库提供的函数,从 _beginthreadex函数的源代码,可以看出它的主要动作是:增加了一个名为ptd的_ptiddata的结构的处理,然后在调用CreateThread函数。_ptiddata是每个线程都拥有自己的专用的数据结构。AfxBeginThread是MFC封装的启动线程的函数,里面包含了很多和MFC相关的启动信息,而且封装了一些常用的操作,使用起来也比较简便。而用另外两个函数就需要程序员对类型,安全性检查进行更多的思考!
引用地址 https://blog.youkuaiyun.com/yangshuangtao/article/details/51284140