多线程学习(一)----CreateThread

来源:互联网 发布:淘宝服装简介怎么写 编辑:程序博客网 时间:2024/05/16 23:39
// tt.cpp : 定义控制台应用程序的入口点。

//同一进程中的多个线程将共享该进程中的全部系统资源,如虚拟地址空间、文件描述符和信号处理等,但是同一个进程中的多个线程都有各自的调用栈、寄存器环境和线程本地存储。

//线程都拥有自己的堆栈,临界区等主要是控制访问全局变量和成员变量


#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <conio.h>

#define WM_NIHAO  1001
#define THREADNUM 3

/*
volatile 修饰符的作用是告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄存器中,并且该值可被外部改变。
对于多线程引用的全局变量来说,volatile 是一个非常重要的修饰符。
*/
volatile int            gInt=0;
//普通临界区
static CRITICAL_SECTION cs;
//MFC临界区
//CCriticalSection        ccs;

//使用原子操作的方法
volatile LONG aomic=100;

void fun(int tNum)
{
    //printf("第%d线程已经工作了\n",tNum);

    if (1)
    {
        //临界区
        EnterCriticalSection(&cs);// 进入临界区,其它线程则无法进入
        //ccs.Lock();
        // 安全访问该区域  
        gInt--;
        printf("第%d线程检测到全局变量gInt的值是:%d\n",tNum,gInt);
        Sleep(0);//致使不使用临界区肯定出错的方法
        gInt++;
        printf("第%d线程检测到全局变量gInt的值是:%d\n",tNum,gInt);
        //ccs.Unlock();
        LeaveCriticalSection(&cs);  // 离开临界区,其它线程可以进入

        //原子操作
        InterlockedIncrement(&aomic);
        InterlockedDecrement(&aomic);
    }

    MSG   msg;   
    //GetMessage 是 从调用线程的消息队列里取得一个消息并将其放于指定的结构。
    //GetMessage不接收属于其他线程或应用程序的消息。获取消息成功后,线程将从消息队列中删除该消息。函数会一直等待直到有消息到来才有返回值。
    //返回值:如果函数取得WM_QUIT之外的其他消息,返回非零值。如果函数取得WM_QUIT消息,返回值是零。如果出现了错误,返回值是-1。
    while(1)
    {   
        int tGM=::GetMessage(&msg,NULL,0,0);
        switch(msg.message)   
        {   
        case WM_NIHAO:   
            printf("第%d线程接收到主线程的发过来的消息:%s\n",tNum,(char*)msg.wParam);
                break;
        default:
            break;
        }

        //不需要接收第二次消息
        if (tGM>0)
        {
            break;
        }
    }

    printf("%d线程结束",tNum);

    //该函数用于线程终结自身的执行,主要在线程的执行函数中被调用。其中参数dwExitCode用来设置线程的退出码。
    //ExitThread(1);
}
int _tmain(int argc, _TCHAR* argv[])
{
    // 在进入多线程环境之前,初始化临界区  
    InitializeCriticalSection(&cs);  

    DWORD threadId[THREADNUM];
    HANDLE hThread[THREADNUM];
    for (int i=0;i<THREADNUM;i++)
    {
        hThread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)fun,(LPVOID)i,CREATE_SUSPENDED,&(threadId[i]));
    }

    while (getch()!='1')
    {
        Sleep(100);
    }
    //试探线程读取全局变量
    gInt=100;
    for (int i=0;i<THREADNUM;i++)
    {
        if (-1==ResumeThread(hThread[i]))
        {
            printf("ResumeThread时候出错了\n");
            return -1;
        }
        
    }
    //ResumeThread线程之后线程投入工作需要一定时间
    Sleep(1000);

    char buff[20]="ni hao ma?";
    for (int i=0;i<THREADNUM;i++)
    {
        BOOL bPostMes=PostThreadMessage(threadId[i],WM_NIHAO,(WPARAM)buff,(LPARAM)strlen(buff));
    }
    //参数一:线程句柄
    //参数二:等待时间(毫秒),IGNORE:不等,INFINITE:死等
    //返回值: WAIT_OBJECT_0: 线程结束
    //           WAIT_TIMEOUT:超过等待时间,指定的对象处于无信号状态
    //           WAIT_ABANDONED:WAIT_ABANDONED_0至(WAIT_ABANDONED_0 + nCount - 1)如果bWaitAll为TRUE,则返回值表明所有指定对象的状态是触发的,并且至少对象之一,是一个废弃的互斥对象。

    //         WAIT_FAILED:出现错误,一般是线程句柄错误

    //WaitForSingleObject函数,此函数的作用是监视hHandle的状态,当监视的句柄为有信号状态时,即此对象为空闲状态时,此函数返回,才能执行其后的代码。

    //WaitForSingleObject(hThread,INFINITE);

    Sleep(1000);
    //值得注意的是hThread数组的所有成员必须全部有效,有一个没效的话,次函数就会执行失败
    DWORD wm=WaitForMultipleObjects(THREADNUM,hThread,true,10000);
    //若果第三个参数是true,则返回值代表所有线程的状态
    //若果第三个参数是false,则返回值代表那个有返回线程的状态
    switch (wm)
    {
    case WAIT_FAILED:
        printf("wm-->WAIT_FAILED\n");
        break;
    case WAIT_TIMEOUT:
        printf("wm-->WAIT_TIMEOUT\n");
        break;

    case WAIT_ABANDONED_0+0:
    case WAIT_ABANDONED_0+1:
    case WAIT_ABANDONED_0+2:
        printf("wm-->WAIT_ABANDONED_0\n");
        break;

    case WAIT_OBJECT_0+0:
    case WAIT_OBJECT_0+1:
    case WAIT_OBJECT_0+2:
        printf("wm-->WAIT_OBJECT_0\n");
        break;

    default:
        break;
    }

    //一般情况下,线程运行结束之后,线程函数正常返回,但是应用程序可以调用TerminateThread强行终止某一线程的执行。
    for (int i=0;i<THREADNUM;i++)
    {
        TerminateThread(hThread[i],0);
    }

    // 释放临界区资源,当不再使用临界区时调用该函数  
    DeleteCriticalSection(&cs);  
    return 0;
}

0 0