认识多线程

线程创建函数介绍


创建线程可以使用系统提供的API函数:CreateThread来完成,该函数将创建一个线程,其函数声明如下:

HANDLE WINAPI CreateThread(
  __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in       SIZE_T dwStackSize,
  __in       LPTHREAD_START_ROUTINE lpStartAddress,
  __in_opt   LPVOID lpParameter,
  __in       DWORD dwCreationFlags,
  __out_opt  LPDWORD lpThreadId
);
下面简单介绍CreateThread函数的每个参数:

lpThreadAttributes

执向LPSECURITY_ATTRIBUTES结构体的指针,使用时我们一般设置为NULL,表示让该线程使用默认的安全性;

dwStackSize

设置线程初始栈的大小,即线程可以将多大的地址空间用于它自己的栈,以字节为单位。默认设置为0,表示使用与调用该函数的线程相同的栈空间大小

lpStartAddress

指向应用程序定义的LPTHREAD_START_ROUTINE类型的函数的指针,表明新线程的起始地址,由新线程执行;这个函数的声明必须是如下形式,函数名字不做要求

DWORD WINAPI ThreadProc(LPVOID lpParameter);

lpParameter

新线程的入参,是LPVOID类型,必要时进行相应类型的强制转换;

dwCreationFlags

设置用于控件线程创建的附加标记,若为0表示线程创建后就立即执行,若为CREATE_SUSPENDED表示创建后处于暂停状态;

lpThreadId

这个是个返回值,指向一个变量,用来接收线程的ID,当线程创建成功后,系统就会分配一个线程ID;如果我们不关心线程ID,我们可以设置为NULL;


实例1


新建一个Win32 Console Application类型的工程,并命名为MultiThread.cpp;

代码如下:

// MultiThread.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std;

//新线程的起始地址
DWORD WINAPI  Thread1Proc(LPVOID lpParameter)
{  
    cout << "Thread1 is ruuning" << endl;

    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE hThread1 = NULL;
    //创建新的线程
    hThread1 = CreateThread(NULL,0,Thread1Proc,NULL,0,NULL);
    //无须对新线程设置优先级等操作,关闭之
    //良好的编码习惯
    CloseHandle(hThread1);

    cout << "main thread is running" << endl;
 
    return 0;
}
我们执行(Ctrl + F5)这段代码多次后,可以发现其结果有三种情况,导致这情况出现的主要原因是:

操作系统为每一个运行的线程安排一个的CPUT时间---时间片。系统通过一种循环方式为线程提供时间片,线程仅在自己的时间内运行,因为时间片非常的短,所以给我们的感觉就像多个线程是同时运行的,每次执行时系统分配的时间片都是不一致的,所以有时候能执到线程1,有时候在主线程的时间片内,主线程已经执行完毕,主线程退出,线程1没有机会执行;

情况1


情况2


情况3



在我们的main函数返回之前,添加一个Sleep(1000)语句,就能确保执行结果和预期一致,即情况3;

解释如下:

Sleep(1000)表示让主线程睡眠1秒,Sleep的入参是毫秒为单位;由于主线程进入睡眠状态,主线程放弃了执行的权利,线程1得到了运行权利,线程1在1秒内足以执行完成,线程1结束;在1秒后,主线程睡醒,主线程执行完毕,程序退出;


实例2


在这个实例中我们引入一个全局的计数器g_Index,在两个线程中分别打印这个index 和执行的线程标识,其代码如下:

int g_nIndex = 0;
const int nMaxCnt = 100;

//新线程的起始地址
DWORD WINAPI  Thread1Proc(LPVOID lpParameter)
{  
    while (g_nIndex++ < nMaxCnt)
    {
        cout <<"Index = "<< g_nIndex << " ";
        cout << "Thread1 is ruuning" << endl;
    }

    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE hThread1 = NULL;
    //创建新的线程
    hThread1 = CreateThread(NULL,0,Thread1Proc,NULL,0,NULL);
    //无须对新线程设置优先级等操作,关闭之
    //良好的编码习惯
    CloseHandle(hThread1);

    while (g_nIndex++ < nMaxCnt)
    {
        cout << "Index = " << g_nIndex << " ";
        cout << "main thread is running" << endl;
    }

    return 0;
}
运行结果:


我们发现某些行的打印和我们的预期有些不符,例如:“Index = 3Index = 2 main thread is running”,这个就是多线程执行带来的问题,可以使用互斥量来解决,这暂不讨论;

同时我们也可以发现主线程和线程1是交替执行的,这里也体现的了多线程的执行是按照时间片来运行的

posted @ 2017-01-08 22:30  小怪兽&奥特曼  阅读(138)  评论(0编辑  收藏  举报