CreateThread简单那多线程编程
作者:vpoet
mail:vpoet_sir@163.com

在进行多任务处理的时候我们往往会用到多线程技术,多线程理论上是多个线程同事处理不同的工作,但是这只针对多核的CPU而言
但是对于单核CPU多线程往往实现的方式是:CPU为各个线程分配时间片,让各个线程循环的执行,但是这个时间片又很短,所以给我
们只管的映像就好像是多个线程在同时工作。
本文主要使用windows API CreateThread函数进行多线程演示。
首先看看MSDN上关于CreateThread函数的说明:
参数说明:
lpThreadAttributes [in] Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If
lpThreadAttributes is NULL, the handle cannot be inherited. 
该参数决定子线程是否继承父进程的安全属性,如果为NULL,表示不继承。关于SECURITY_ATTRIBUTES结构体请查询MSDN
dwStackSize [in] Specifies the initial commit size of the stack, in bytes. The system rounds this value to the nearest page. If this value is zero, or is smaller than the default commit size, the default is to use the same size as the calling thread. For more information,
see Thread Stack Size
该参数指定线程堆栈大小,如果该值为零则使用默认的线程堆栈大小
lpStartAddress [in] Pointer to the application-defined function of type LPTHREAD_START_ROUTINE to be executed by the thread and represents the starting address of the thread. For more information on the thread function, see
ThreadProc
该参数则指定线程函数地址,说白了就是线程函数名
lpParameter [in] Specifies a single parameter value passed to the thread. 
该参数为传递给线程函数的参数
dwCreationFlags [in] Specifies additional flags that control the creation of the thread. If the CREATE_SUSPENDED flag is specified, the thread is created in a suspended state, and will not run until the
ResumeThread function is called. If this value is zero, the thread runs immediately after creation. At this time, no other values are supported. 
该参数为创建标识,如果为零,那么线程创建后会立即执行,若为CREATE_SUSPENDED则线程创建后则会停止
lpThreadId [out] Pointer to a variable that receives the thread identifier. 
该参数为创建线程的线程ID,线程ID就是唯一标识该线程的一个数字

那么现在我们来写一个最简单的多线程例子:

#include <windows.h>
#include "stdio.h" DWORD WINAPI ThreadOne(LPVOID lpParameter)
{
printf("ThreadOne is Runing\n");
Sleep(100);
return 0;
} int main()
{
HANDLE HOne;
printf("***********************vpoet******************\n");
HOne=CreateThread(NULL,0,ThreadOne,NULL,0,NULL);
printf("ThreadOne Begin!\n");
CloseHandle(HOne);
printf("MainThread Over!\n");
return 0;
}

运行结果:
咦!是不是看出来什么问题了,子线程貌似没有运行主线程就退出了,这是怎么回事呢,这说明当开启子线程后还未来得及运行主线程就已经执行完毕,并且return了,那么此时整个程序也就退出,当然也就不会再运行子线程了。那么我们应该怎么控制了,既然子线程来不及执行,那么我就让主线程多运行一会儿等到子线程执行完了之后主线程再退出。是不是很有道理,恩,我也觉得。
那么我们在

printf("MainThread Over!\n");

之前再加入一句代码

Sleep(1000)

让主线程延时1s等待子线程的执行。因为1s足够让子线程执行完毕了所以这次程序就会在子线程运行结束后正常退出了。运行结果如下:
看吧,这下是正常退出了吧。

当然还有其他方法来等待子线程正常执行并返回,对了还有个HOne这玩意儿还没有介绍,
Handle其实就是一个句柄对象,就像是一个结构体或者类一样,只不过它是内核对象,由内核
自己维护。为啥需要CloseHand()呢 百度百科是这样说的:
关闭一个内核对象。其中包括文件、文件映射、进程、线程、安全和同步对象等。在CreateThread成功之后会返回一个hThread的handle,且内核对象的计数加1,CloseHandle之后,引用计数减1,当变为0时,系统删除内核对象。
若在线程执行完之后,没有调用CloseHandle,在进程执行期间,将会造成内核对象的泄露,相当于句柄泄露,但不同于内存泄露,这势必会对系统的效率带来一定程度上的负面影响。但当进程结束退出后,系统会自动清理这些资源。

那么我们就需要知道线程到底是什么时候退出的呢,然后在其退出的时候把该线程句柄Close掉。

这里要介绍一个API叫WaitForSingleObject;
我们MSDN一下:

MSDN这样说该函数只有在以下两种情况下才返回:
1.指定的对象有信号状态时
2.等待超时
那到底是什么意思呢,别着急,我们再看看参数:
hHandle [in] Handle to the object. For a list of the object types whose handles can be specified, see the following Remarks section.

If this handle is closed while the wait is still pending, the function's behavior is undefined.

该参数是一个句柄对象,如果句柄已经Close掉后还在WaitForSingleObject那么这种情况是未定义的,未定义是啥意思了就是会有意想不到的效果,
说白了就是重大的隐藏的BUG
dwMilliseconds [in] Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the object's state is nonsignaled. If
dwMilliseconds is zero, the function tests the object's state and returns immediately. If
dwMilliseconds is INFINITE, the function's time-out interval never elapses. 
该参数是指定超时间隔,如果参数为零则函数马上返回,如果参数为INFINITE,函数会一直等待。
另外该函数的返回值有主要有两种状态:
WAIT_OBJECT_0 The state of the specified object is signaled. 表示句柄为有信号状态时候返回
WAIT_TIMEOUT The time-out interval elapsed, and the object's state is nonsignaled. 表示等待超时返回
现在我们去掉主函数的Sleep延时1s的代码,在CreateThread()后面加上一句:
WaitForSingleObject(HOne,INFINITE);

现在我们再看看运行结果:

果然正确,现在明白WaitForSingleObject(HOne,INFINITE);的意思了吧

版权声明:本文为博主原创文章,未经博主允许不得转载。

CreateThread简单那多线程编程的更多相关文章

  1. Linux下简单的多线程编程--线程池的实现

    /* 写在前面的话: 今天刚“开原”,选择了一篇关于线程池的文件与大家分享,希望能对您学习有所帮助,也希望能与大家共同学习! 选择在这个特殊的时候注册并发文章也是有一些我个人特殊的意义的,看我的id( ...

  2. 数据结构(逻辑结构,物理结构,特点) C#多线程编程的同步也线程安全 C#多线程编程笔记 String 与 StringBuilder (StringBuffer) 数据结构与算法-初体验(极客专栏)

    数据结构(逻辑结构,物理结构,特点) 一.数据的逻辑结构:指反映数据元素之间的逻辑关系的数据结构,其中的逻辑关系是指数据元素之间的前后件关系,而与他们在计算机中的存储位置无关.逻辑结构包括: 集合 数 ...

  3. 【转】 Linux下的多线程编程

    作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/原文链接:http://www.cnblogs.com/gnuhpc/archive/2012/12/07/280 ...

  4. Linux下的多线程编程

    1 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者.传统的 Unix也支持线程的概念,但是在一个进程(proces ...

  5. Linux下多线程编程

    一.为什么要引入线程? 使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式.在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维 ...

  6. 【转】Linux下的多线程编程

    1 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者.传统的 Unix也支持线程的概念,但是在一个进程(proces ...

  7. 《转》Linux下的多线程编程

    原地址:http://linux.chinaunix.net/doc/program/2001-08-11/642.shtml 1 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程 ...

  8. C#多线程编程的同步也线程安全

    前一篇文章记录了简单的多线程编程的几种方式,但是在实际的项目中,也需要等待多线程执行完成之后再执行的方法,这个就叫做多线程的同步,或者,由于多个线程对同一对象的同时操作造成数据错乱,需要线程安全.这篇 ...

  9. ZT 为什么pthread_cond_t要和pthread_mutex_t同时使用 || pthread/Linux多线程编程

    为什么线程同步的时候pthread_cond_t要和pthread_mutex_t同时使用 (2009-10-27 11:07:23) 转载▼ 标签: 杂谈 分类: 计算机 举一个例子(http:// ...

随机推荐

  1. Shortest Word Distance 解答

    Question Given a list of words and two words word1 and word2, return the shortest distance between t ...

  2. html 表单初步学习

    <html> <head> <title> 静态页面</title> </head> <body> 这是一个静态页面<br ...

  3. OpenStackCLI调试及术语识记

    1,Project are organizational units in the cloud,and are also known as tenants or accounts.Each user ...

  4. bootstrap 导航布局

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  5. PHP批量审核ajax jquery

    var jQuery = $.noConflict(); // alert(jQuery); jQuery(document).ready(function() { /*批量审核*/ jQuery(' ...

  6. IOS 退出App

    UIApplication *app = [UIApplication sharedApplication]; [app performSelector:@selector(suspend)]; // ...

  7. JVM结构、GC工作机制详解

      JVM结构.内存分配.垃圾回收算法.垃圾收集器.下面我们一一来看. 一.JVM结构 根据<java虚拟机规范>规定,JVM的基本结构一般如下图所示: 从左图可知,JVM主要包括四个部分 ...

  8. poj1410

    简单题,注意是实心矩形 #include <iostream> #include <math.h> #include <iomanip> #define eps 1 ...

  9. Linux内核:sk_buff解析

    sk_buff 目录 1 sk_buff介绍 2 sk_buff组成 3 struct sk_buff 结构体 4 sk_buff成员变量 4.1 Layout布局 4.2 General通用 4.3 ...

  10. 《JavaScript 闯关记》之原型及原型链

    原型链是一种机制,指的是 JavaScript 每个对象都有一个内置的 __proto__ 属性指向创建它的构造函数的 prototype(原型)属性.原型链的作用是为了实现对象的继承,要理解原型链, ...