c语言createthread函数,C++中CreateThread函数创建线程的用法和实例

c语言createthread函数,C++中CreateThread函数创建线程的用法和实例CreateThread是一种微软在WindowsAPI中提供了建立新的线程的函数,该函数在主线程的基础上创建一个新线程。线程终止运行后,线程对象仍然在系统中,必须通过CloseHandle函数来关闭该线程对象。需要调用到CRT库时,不要用CreateThread创建线程、并用CloseHandle来关闭这个线程,而应该用_beginthread来创建线程,_endthread来销毁线程。因为…

大家好,又见面了,我是你们的朋友全栈君。

CreateThread是一种微软在Windows API中提供了建立新的线程的函数,该函数在主线程的基础上创建一个新线程。线程终止运行后,线程对象仍然在系统中,必须通过CloseHandle函数来关闭该线程对象。

需要调用到CRT库时,不要用CreateThread 创建线程、并用CloseHandle来关闭这个线程,而应该用_beginthread来创建线程,_endthread来销毁线程。因为没有对子线程为CRT库分配堆,会导致低内存错误而崩溃。

CreateThread 不会判断lpStartAddr是数据还是代码,甚至不会判断是否有足够的访问权限。lpStartAddr可以未必是个函数,也可以是类成员,只要将函数指针强制转换,并且不产生栈溢出和没有访问权限的问题就以及类如未定义的指令之类的错误可以顺利执行线程。创建类成员函数的对象时,this指针是调用CreateThread时所处的类对象的指针。在类对象外调用,其this指针将是未知的。

什么是线程

1、在Windows平台上,最终可以利用CPU执行代码的最小尸体就是线程

2、首先从内核角度看,线程是一个内核对象,系统用它来村塾一些关于线程统计信息(比如时间)

3、从编程角度来看,线程是一堆寄存器状态以及线程栈的一个结构体对象,本质上可以理解为一个函数调用其(

寄存器状态用与控制CPU执行,栈用于存储局部变量和函数调用参数及函数返回地址)

4、最后需要知道的就是线程还可以带有几个队列(简单的理解为异步函数调用队列):

消息队列(GUI线程系统内部会创建)

APC队列(调用APC函数时会创建)

(注意:这些队列在线程创建时比并不存在)

5、线程就是执行体

什么时候不使用线程

1、当一个算法是严格穿行化的时候,也就是计算的每一步都严重以来前一个操作步骤的结果的时候

2、当有多个功能任务也具有比较严格的先后逻辑关系的时候,不宜采用多线程

3、还有一个特殊情况,比如一个服务器需要处理成千上万个客户端链接,并处理不同的请求的时候,这种

情况下应当优先考虑线程池,而不是简单的多线程。

默认的线程函数必须具有如下原型

DWORD WINAPI ThreadProc(LPVOID LpParameter);

调用API:CreateThread可以创建一个新进程HANDLE WINAPI CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttributes,

SIZE_T dwStackSize,

LPTHREAD_START_ROUTINE lpStartAddress,

LPVOID lpParameter,

DWORD dwCreationFlags,

LPDWORD lpThreadId

);

其中安全属性参数指定的是创建新进程内核对象的安全属性,不是线程访问字符串(Token)的属性

dwStackSize用于指定线程初始时的栈大小,通常传入0即可,此时系统会使用一个合适的大小

lpStartAddress就是新进程入口函数的地址

lpParameter就是传入线程入口的参数,这个参数完全由调用者使用,系统只是简单的将这个参数

传递给线程函数,并不做别的任何处理

dwCreationFlags指出创建线程的方式,如果是0,表示线程一被创建就被立即执行,如果是CREATE_SUSPENDED,

表示线程一被创建先暂停,并不执行,在XP以上的系统中此参数还可以结合一个STACK_SIZE_PARAM_IS_A_RESERVATION

用于指出设置dwStackSize起始只是为线程栈保留的虚拟地址空间的大小,并不需要实际提交那么多的物理页面

如果没有指定这个标志位,那么dwStackSize也是实际提交内存的大小值

lpThreadId则用于得到线程唯一的标识符

1、参数的结果是随机的,表明CPU调用线程完全是随机的

2、这充分说明Windows线程调度机制的最终行为是随机的,是一个抢占式多任务的系统

3、因此分析多线程程序的时候,一般不能假设某个线程会被先调度,某个线程会被后调度,也即

不能假设线程执行的顺序这样的行为

4、虽然windows调度程序时间是按分时多任务方式来轮流调度线程的,而且这个时间片是20ms,

但是从宏观的角度来看,比如1秒的时间粒度,这些线程可以被认为是“同时”运行的

5、这些信息说明,无论线程调度如何执行,在分析时始终认为这些线程实际上时并行执行的,

这样就可以把繁琐的分析简单化

6、下面的例子只是用了一个线程函数,而这个函数起始访问了一个公共资源STDOUTPUT

7、在windows系统中,大多数内核对象的操作室严格穿行化的,因此无论线程如何并发的执行,

最终输出的结果都是完整有序的,因为调用的WriteConsole方法本身是严格串行化的(否则输出是混乱的)

8、有时虽然线程本身是被认为是并发的,但在实际中又确实需要对他们执行的顺序进行一些不要的控制和管理,

这是就需要进行多线程并发控制

#include

#include

#include

#include

#define GRS_ALLOC(sz) HeapAlloc(GetProcessHeap(),0,sz)

#define GRS_CALLOC(sz) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz)

#define GRS_SAFEFREE(p) if(NULL!=p){HeapFree(GetProcessHeap(),0,p);p=NULL;}

#define GRS_USEPRINTF() TCHAR pBuf[1024]={}

#define GRS_PRINTF(…)\

StringCchPrintf(pBuf, 1024, __VA_ARGS__); \

WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), pBuf, lstrlen(pBuf), NULL, NULL);

#define MAX_THREADS 10 //最大线程数

DWORD WINAPI MyThreadFunction(LPVOID lpParam);

void ErrorHandler(LPTSTR lpszFunction);

//自定义线程数据

typedef struct MyData

{

int val1;

int val2;

}MYDATA, *PMYDATA;

int _tmain()

{

PMYDATA pDataArray[MAX_THREADS];

DWORD dwThreadIdArray[MAX_THREADS];

HANDLE hThreadArray[MAX_THREADS];

//创建线程循环

for (int i = 0; i 

{

pDataArray[i] = (PMYDATA)GRS_CALLOC(sizeof(MYDATA));

pDataArray[i]->val1 = i;

pDataArray[i]->val2 = i + 100;

hThreadArray[i] = CreateThread(NULL, 0, MyThreadFunction, pDataArray[i], 0, &dwThreadIdArray[i]);

if (hThreadArray[i] == NULL)

{

ErrorHandler(_T(“CreateThread”));

ExitProcess(3);

}

}

WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);

for (int i = 0; i 

{

CloseHandle(hThreadArray[i]);

GRS_SAFEFREE(pDataArray[i]);

}

_tsystem(_T(“PAUSE”));

return 0;

}

DWORD WINAPI MyThreadFunction(LPVOID lpParam)

{

//线程函数

GRS_USEPRINTF();

PMYDATA pDataArray = (PMYDATA)lpParam;

GRS_PRINTF(_T(“Parameters=%d,%d\n”),pDataArray->val1,pDataArray->val2);

return 0;

}

void ErrorHandler(LPTSTR lpszFunction)

{

GRS_USEPRINTF();

LPVOID lpMsgBuf;

DWORD dw = GetLastError();

FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |

FORMAT_MESSAGE_FROM_SYSTEM |

FORMAT_MESSAGE_IGNORE_INSERTS,

NULL,

dw,

MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),

(LPTSTR)&lpMsgBuf,

0,NULL

);

GRS_PRINTF(_T(“%s failed with error %d:%s”),lpszFunction,dw,lpMsgBuf);

LocalFree(lpMsgBuf);

C++ 多线程 CreateThread函数使用例1

#include 

#include 

#include 

#include 

#include 

#include 

#include 

//头文件引用较多, 有一些与本程序无关

/*

HANDLE WINAPI CreateThread(

LPSECURITY_ATTRIBUTES   lpThreadAttributes, //线程安全相关的属性,常置为NULL

SIZE_T                  dwStackSize,        //新线程的初始化栈在大小,可设置为0

LPTHREAD_START_ROUTINE  lpStartAddress,     //被线程执行的回调函数,也称为线程函数

LPVOID                  lpParameter,        //传入线程函数的参数,不需传递参数时为NULL

DWORD                   dwCreationFlags,    //控制线程创建的标志

LPDWORD                 lpThreadId          //传出参数,用于获得线程ID,如果为NULL则不返回线程ID

);

*/

using namespace std;

volatile int b = 0;

DWORD WINAPI ThreadProc(LPVOID lpParameter)

{

int i = 10000;

int *p = (int*)lpParameter;

while(i–)

{

(*p)++;

b++;

}

return 0;

}

int main(int argc, char* argv[])

{

int a = 0;

HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc, &a, 0, NULL);

HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc, &a, 0, NULL);

HANDLE hThread3 = CreateThread(NULL, 0, ThreadProc, &a, 0, NULL);

HANDLE hThread4 = CreateThread(NULL, 0, ThreadProc, &a, 0, NULL);

HANDLE hThread5 = CreateThread(NULL, 0, ThreadProc, &a, 0, NULL);

Sleep(1000);

CloseHandle(hThread1);

CloseHandle(hThread2);

CloseHandle(hThread3);

CloseHandle(hThread4);

CloseHandle(hThread5);

cout <

cout <

system(“pause”);

return 0;

}

使用实例2:

1.定义的全局变量DWORD WINAPI ClientThread(LPVOID lpParam);

struct ClientInfo

{

SOCKET sock;

SOCKADDR_IN clientAddr;定义地址族

};

2.使用方法HANDLE hThread; DWORD dwThread;

struct ClientInfo *pClientInfo=NULL;

pClientInfo=(struct ClientInfo *)malloc(sizeof(struct ClientInfo));

hThread = CreateThread(NULL,0,ClientThread,(LPVOID)pClientInfo,0,&dwThread);   //free(pClientInfo);   if(hThread==NULL)   {    AfxMessageBox(“Thread Creat Failed!\n”);    return;   }

CloseHandle(hThread);3.线程函数的实现DWORD WINAPI ClientThread(LPVOID lpParam){ struct ClientInfo *pClinetInfo=(struct ClientInfo *)lpParam;     SOCKET sock = pClinetInfo->sock; SOCKADDR_IN addrClient=pClinetInfo->clientAddr; free(lpParam);    CTCPServerDlg *dlg=(CTCPServerDlg*)AfxGetApp()->GetMainWnd();

while(1)

{

…..

Sleep(200);

}

return 0;

实例3://ThreadBase.h
#pragma once#includeclass CThreadBase

{public:

CThreadBase(void);    ~CThreadBase(void);    static DWORD WINAPI ThreadProc (PVOID pParam);    virtual void Run() = 0;    void Start();

private:

HANDLE m_hThread;

DWORD  m_dwThreadID;

};

//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);

}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/162688.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • java激活码_在线激活

    (java激活码)最近有小伙伴私信我,问我这边有没有免费的intellijIdea的激活码,然后我将全栈君台教程分享给他了。激活成功之后他一直表示感谢,哈哈~https://javaforall.cn/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~S32P…

  • aspectjweaver.jar包下载

    aspectjweaver.jar包下载点击链接https://www.eclipse.org/aspectj/downloads.php点击下载后得到一个jar文件:用解压工具解压:就看到aspectjweaver.jar包了。

  • java获取Date时间的各种方式汇总「建议收藏」

    java获取Date时间的各种方式汇总「建议收藏」1. 常用的时间获取方式public class DateUtils {   /**   * 获取时间戳   * 输出结果:1438692801766   */  @Test  public void getTimeStamp() {    Date date = new Date();    long times = date.getTime();    System.o…

  • 时间复杂度是什么_时间复杂度的表示方法

    时间复杂度是什么_时间复杂度的表示方法-宝宝为啥听不懂他们在讨论的时间复杂度0.0-我怎么知道这个算法运行得比那个算法快0.0-我究竟会不会超时0.0-我为什么还会超时0.0-时间复杂度怎么算0.0在别人还不会求时间复杂度的时候而你会了是不是很酷在别人都会求时间复杂度的时候而你不会是不是很尴尬千里之行始于足下希望这篇文章能祝你一臂之力=w= 此篇详解,希望能帮助各位稍微解决一下不解=w=…

  • Redis的缓存雪崩、缓存击穿、缓存穿透与缓存预热、缓存降级

    Redis的缓存雪崩、缓存击穿、缓存穿透与缓存预热、缓存降级

  • pytest指定用例_文件夹排列顺序自定义

    pytest指定用例_文件夹排列顺序自定义前言测试用例在设计的时候,我们一般要求不要有先后顺序,用例是可以打乱了执行的,这样才能达到测试的效果.有些同学在写用例的时候,用例写了先后顺序,有先后顺序后,后面还会有新的问题(如:上个用例返回

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号