栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

线程Thread(C++)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

线程Thread(C++)

总结有关创建线程的问题有四种方法:

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, //是线程堆栈大小,一般默认为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创建一个线程
#include //头文件
#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;
}
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 
#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的。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/429789.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号