多线程入门(一CreateThread与_beginthreadex)

用CreateThread创建多线程

#include<iostream>
#include<windows.h>

DWORD WINAPI ThreadFun(LPVOID pM)
{
    printf("子线程的线程ID号为:%d\n子线程输出Hello World\n",GetCurrentThreadId());
    return 0;
}

int main()
{
    printf("最简单的创建多线程\n");
    printf("--by MoreWindows(http://blog.csdn.net/MoreWindows)--\n\n");

    HANDLE handle=CreateThread(NULL,0,ThreadFun,NULL,0,NULL);
    WaitForSingleObject(handle,INFINITE);
    return 0;
}

HANDLE CreateThread
第一个参数:表示线程内核对象的安全属性,一般传入NULL表示使用默认设置。
第二个参数:表示线程栈空间大小。传入0表示使用默认大小(1MB)
第三个参数:表示新线程所执行的线程函数地址,多个线程可以使用同一个函数地址。
第四个参数:表示传给线程函数的参数。
第五个参数:表示指定额外的标识来控制线程的创建,为0表示线程创建后就可以进行调度。
如果为CREATE_SUSPENDED则表示线程创建后暂停运行,这样它就无法调度,直到调用ResumeThread()。
第六个参数:将返回线程的ID号,传入NULL表示不需要返回该线程ID号。
WaitForSingleObject
函数功能:等待函数-是线程进入等待状态,知道指定的内核对象被处罚。
第一个参数:要等待的内核对象。
第二个参数:最长等待时间。
CreateTread与——beginthreadex的区别
根本原因:编写标准c运行库的程序员根本没有考虑多线程程序使用标准C运行库的情况。比如标准C运行库的全局变量errno。很多运行库中的函数在出错时会将错误代号赋值给这个全局变量,

if (system("notepad.exe readme.txt") == -1)  
{  
    switch(errno)  
    {  
        ...//错误处理代码  
    }  
}  

假设某个线程A再执行上面的代码,该线程在调用system()之后尚未调用switch(语句时)另外一个线程B启动了,这个线程B也调用了biaozhunc运行库的函数,不幸的是这个函数执行出错了并将错误代码写入全局变量errno中。这样线程A一旦开始执行switch()语句时,它将访问一个被B线程改动了的errno。

解决方案
windows 每个线程都将拥有自己专用的一块内存区域来提供标准c运行库中所有有需要的函数使用。而且这块内存区域的创建就是有C/C++运行库函数_beginthreadex()

//创建多子个线程实例  
#include <stdio.h>  
#include <process.h>  
#include <windows.h> 

int g_nCount;
//子线程函数  
unsigned int __stdcall ThreadFun(PVOID pM)
{
    g_nCount++;
    printf("线程ID号为%4d的子线程说%d\n",GetCurrentThreadId(),g_nCount);
    return 0;
}
int main()
{
    printf("创建多个子线程实例\n");
    printf("--by MorreWindows(http://blog.csdn.net/MoreWindows)--\n\n");

    const int THREAD_NUM=5;
    HANDLE handle[THREAD_NUM];

    g_nCount=0;
    for(int i=0;i<THREAD_NUM;i++)
    {
        handle[i]=(HANDLE)_beginthreadex(NULL,0,ThreadFun,NULL,0,NULL);
    }
    WaitForMultipleObjects(THREAD_NUM,handle,TRUE,INFINITE);
    return 0;
}


由上面的源代码可知,_beginthreadex()函数在创建新线程时会分配并初始化一个_tiddata块。这个_tiddata块自然是用来存放一些需要线程独享的数据。事实上新线程运行时会首先将_tiddata块与自己进一步关联起来。然后新线程调用标准C运行库函数如strtok()时就会先取得_tiddata块的地址再将需要保护的数据存入_tiddata块中。这样每个线程就只会访问和修改自己的数据而不会去篡改其它线程的数据了。因此,如果在代码中有使用标准C运行库中的函数时,尽量使用_beginthreadex()来代替CreateThread()。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值