多线程编程入门(一)

多线程简介

1: 什么是多线程

多线程,是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。
初学者经常混淆线程与进程的概念,进程是一个应用程序正在运行的程序实例,只有运行了.exe之类的程序才会产生一个进程实例,一个应用程序可以对应多个程序,例如打开多个chrome网页就是运行chrome程序的多个进程实例。进程是不执行代码段的,他只是线程的容器,真正完成代码段的就是所谓的线程。单个进程包含至少一个进程,来执行进程地址空间的代码段。当创建一个进程时,操作系统会自动创建该进程的一个线程,叫做主线程,也就是执行main函数或者WinMain函数的线程。此后主线程可以创建其他进程。

2: 创建多线程程序

创建线程可以使用API函数CreateThread函数来完成,该函数的原型如下:

CreateThread(
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
    _In_ SIZE_T dwStackSize,
    _In_ LPTHREAD_START_ROUTINE lpStartAddress,
    _In_opt_ __drv_aliasesMem LPVOID lpParameter,
    _In_ DWORD dwCreationFlags,
    _Out_opt_ LPDWORD lpThreadId
    );

函数说明:
第一个参数表示线程内核对象的安全属性,一般传入NULL表示使用默认设置。
第二个参数表示线程栈空间大小。传入0表示使用默认大小(1MB)。
第三个参数表示新线程所执行的线程函数地址,多个线程可以使用同一个函数地址。
第四个参数是传给线程函数的参数。
第五个参数指定额外的标志来控制线程的创建,为0表示线程创建之后立即就可以进行调度,如果为CREATE_SUSPENDED则表示线程创建后暂停运行,这样它就无法调度,直到调用ResumeThread()。
第六个参数将返回线程的ID号,传入NULL表示不需要返回该线程ID号。
函数返回值:
成功返回新线程的句柄,失败返回NULL。

#include
#include
#include
int index = 0;
DWORD WINAPI ThreadProc(LPVOID IpParameter);

void main()
{
    HANDLE hThread1;
    hThread1 = CreateThread(NULL,0,ThreadProc,NULL,0,NULL);

    CloseHandle(hThread1);      
    std::cout<<"main thread is running!"<<std::endl;
    //Sleep(10000);
    system("pause");
}

DWORD WINAPI ThreadProc(LPVOID IpParameter)
{
    std::cout<<"thread1 is running!"<<std::endl;
    return 0;
}

运行结果如下:
多线程编程入门(一)_第1张图片
从结果可以看到,在主函数代码段输出“main thread is running”后是有一个换行的,可是结果并没有显示,这是因为操作系统会为安排一定的CPU运行时间——时间片,一个线程只能在在自己的时间片内运行,但是两个进程却共用一个显示打印的设备资源,也就是,在main中显示完“main thread is running”后,在准备输出endl的时候用完了自己的时间片(实际是输出endl时需要缓冲区消耗时间)这时候CPU开始运行ThreadProc这个线程,所以就直接输出了”thread1 is running!”

那么如何修改代码呢?
1):输出

std::cout<<"main thread is running!\n";
std::cout<<"thread1 is running!\n";

此时输出只有一个指令;
2):使用CreateMutex()函数
该函数通过建立互斥对象,确保线程拥有对单个资源的互斥访问权限;(就是,在主线程打印字符串的时候ThreadProc线程不会插入);
改进后的代码如下:

#include<Windows.h>
#include<iostream>
#include<iomanip>
HANDLE hMutex;               //定义一个互斥对象,全局变量;
DWORD WINAPI ThreadProc(LPVOID IpParameter);

void main()
{
    hMutex = CreateMutex(NULL,FALSE,NULL);

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

    CloseHandle(hThread1);
    WaitForSingleObject(hMutex,INFINITE);
    std::cout<<"main thread is running!"<<std::endl;
    ReleaseMutex(hMutex);
    //Sleep(10000);
    system("pause");
}

DWORD WINAPI ThreadProc(LPVOID IpParameter)
{
    WaitForSingleObject(hMutex,INFINITE);
    std::cout<<"thread1 is running!"<<std::endl;
    ReleaseMutex(hMutex);
    return 0;
}

此时运行结果如下:
多线程编程入门(一)_第2张图片
使用互斥对象后,线程不会主动的使用资源,必须加上WaitForSingleObject函数主动请求共享对象的使用权,该函数两个参数,前一个参数表示请求对象的句柄,后一个是指定等待时间的间隔,使用完成后还需要ReleaseMutex(hMutex)来释放该资源的试使用权。

参考目录:
鸡啄米入门经典实例
秒杀多线程第二篇 多线程第一次亲密接触 CreateThread与_beginthreadex本质区别

你可能感兴趣的:(C++,MFC/VC++,多线程,编程,线程)