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

}

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • vue md5.js_VUE.js

    vue md5.js_VUE.js<template><div><mavonEditorv-model=”markdown”:codeStyle=”codeStyle”></mavonEditor><divv-html=”compiledMarkdown”></div></div></template><script>//编辑import{mavonEditor}from’.

    2022年9月2日
    3
  • Python表白代码:太秀了,用过的人都找到了对象…【满屏玫瑰盛开】

    Python表白代码:太秀了,用过的人都找到了对象…【满屏玫瑰盛开】导语暗恋让人受尽委屈!一开始,你是我的秘密,我怕你知道,又怕你不知道,又怕你知道装作不知道!这大概就是暗恋的感受吧,可若是双向奔赴,那简更是甜蜜度爆表,快同小编吃下这波狗粮!跟着上一期的玫瑰花花样表白之后,小编新出了2款新型升级之后的表白代码!花样表白总有一款是你喜欢的!效果满分~正文还是熟悉的配方!熟悉的味道!盛开的蓝玫瑰效果如下:附源码:t.setup(800,800)t.hideturtle()t.speed(11)t.penup().

    2022年5月5日
    98
  • 国内做得好的hr系统_平安hrx下载

    国内做得好的hr系统_平安hrx下载HR专家训练营-X版本成为HR专家系列(X版本)链接:https://pan.baidu.com/s/1–jD9mySf2dIcGKEG-4LYw提取码:8boq备用链接天翼云盘下载不限速,建议使用天翼云下载速度会更快一些https://cloud.189.cn/t/ua2MfmQN7Bnq(访问码:6p4z){1}–课程简介{10}–干部管理{11}–企业文化{1…

    2025年8月26日
    4
  • linux监控系统catic,网络设备监控-Catic添加H3C的监控图解[通俗易懂]

    linux监控系统catic,网络设备监控-Catic添加H3C的监控图解[通俗易懂]网络设备监控-Catic添加H3C的监控图解作者:尹正杰版权声明:原创作品,谢绝转载!否则将追究法律责任。首先,我要声明满足2个条件才能作本篇笔记的操作:第一:你得有台cacti服务器,第二:你得有台交换机,这台交换机需要配置团体名并且可以和你的cacti服务器互通。以上两点我已经在之前的笔记分享过,这里我就不啰嗦啦,直接上图。对了,如果你懒得部署Cacti的话,也可以直接用网上的别人做好的iso…

    2025年7月27日
    3
  • 数据结构——HashMap

    数据结构——HashMap众所周知,HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry。这些个键值对(Entry)分散存储在一个数组当中,这个数组就是HashMap的主干。HashMap数组每一个元素的初始值都是Null。对于HashMap,我们最常使用的是两个方法:Get和Put。1.Put方法的原理调用Put方法的时候发生了什么呢?…

    2022年5月12日
    44
  • pycharm怎么换行_pycharm有几个版本

    pycharm怎么换行_pycharm有几个版本pycharm设置自动换行1.代码编辑区自动换行对所有文件有效:(1)File->Settings->Editor->General(2)找到SoftWraps,勾选Soft-wrapfiles(3)在输入框中添加;*.py,如下图所示2.控制台console自动换行File->Settings->Editor->G…

    2022年8月27日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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