zoukankan      html  css  js  c++  java
  • 多线程学习----CreateThread

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

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

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

      1 #include "stdafx.h"
      2 #include <Windows.h>
      3 #include <stdio.h>
      4 #include <conio.h>
      5 
      6 #define WM_NIHAO  1001
      7 #define THREADNUM 3
      8 
      9 /*
     10 volatile 修饰符的作用是告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄存器中,并且该值可被外部改变。
     11 对于多线程引用的全局变量来说,volatile 是一个非常重要的修饰符。
     12 */
     13 volatile int            gInt=0;
     14 //普通临界区
     15 static CRITICAL_SECTION cs;
     16 //MFC临界区
     17 //CCriticalSection        ccs;
     18 
     19 //使用原子操作的方法
     20 volatile LONG aomic=100;
     21 
     22 void fun(int tNum)
     23 {
     24     //printf("第%d线程已经工作了
    ",tNum);
     25 
     26     if (1)
     27     {
     28         //临界区
     29         EnterCriticalSection(&cs);// 进入临界区,其它线程则无法进入
     30         //ccs.Lock();
     31         // 安全访问该区域  
     32         gInt--;
     33         printf("第%d线程检测到全局变量gInt的值是:%d
    ",tNum,gInt);
     34         Sleep(0);//致使不使用临界区肯定出错的方法
     35         gInt++;
     36         printf("第%d线程检测到全局变量gInt的值是:%d
    ",tNum,gInt);
     37         //ccs.Unlock();
     38         LeaveCriticalSection(&cs);  // 离开临界区,其它线程可以进入 
     39 
     40         //原子操作
     41         InterlockedIncrement(&aomic);
     42         InterlockedDecrement(&aomic);
     43     }
     44 
     45     MSG   msg;   
     46     //GetMessage 是 从调用线程的消息队列里取得一个消息并将其放于指定的结构。
     47     //GetMessage不接收属于其他线程或应用程序的消息。获取消息成功后,线程将从消息队列中删除该消息。函数会一直等待直到有消息到来才有返回值。
     48     //返回值:如果函数取得WM_QUIT之外的其他消息,返回非零值。如果函数取得WM_QUIT消息,返回值是零。如果出现了错误,返回值是-1。
     49     while(1)
     50     {   
     51         int tGM=::GetMessage(&msg,NULL,0,0);
     52         switch(msg.message)   
     53         {   
     54         case WM_NIHAO:   
     55             printf("第%d线程接收到主线程的发过来的消息:%s
    ",tNum,(char*)msg.wParam);
     56                 break;
     57         default:
     58             break;
     59         } 
     60 
     61         //不需要接收第二次消息
     62         if (tGM>0)
     63         {
     64             break;
     65         }
     66     }
     67 
     68     printf("%d线程结束",tNum);
     69 
     70     //该函数用于线程终结自身的执行,主要在线程的执行函数中被调用。其中参数dwExitCode用来设置线程的退出码。
     71     //ExitThread(1);
     72 }
     73 int _tmain(int argc, _TCHAR* argv[])
     74 {
     75     // 在进入多线程环境之前,初始化临界区  
     76     InitializeCriticalSection(&cs);  
     77 
     78     DWORD threadId[THREADNUM];
     79     HANDLE hThread[THREADNUM];
     80     for (int i=0;i<THREADNUM;i++)
     81     {
     82         hThread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)fun,(LPVOID)i,CREATE_SUSPENDED,&(threadId[i]));
     83     }
     84 
     85     while (getch()!='1')
     86     {
     87         Sleep(100);
     88     }
     89     //试探线程读取全局变量
     90     gInt=100;
     91     for (int i=0;i<THREADNUM;i++)
     92     {
     93         if (-1==ResumeThread(hThread[i]))
     94         {
     95             printf("ResumeThread时候出错了
    ");
     96             return -1;
     97         }
     98         
     99     }
    100     //ResumeThread线程之后线程投入工作需要一定时间
    101     Sleep(1000);
    102 
    103     char buff[20]="ni hao ma?";
    104     for (int i=0;i<THREADNUM;i++)
    105     {
    106         BOOL bPostMes=PostThreadMessage(threadId[i],WM_NIHAO,(WPARAM)buff,(LPARAM)strlen(buff));
    107     }
    108     //参数一:线程句柄
    109     //参数二:等待时间(毫秒),IGNORE:不等,INFINITE:死等
    110     //返回值: WAIT_OBJECT_0: 线程结束
    111     //           WAIT_TIMEOUT:超过等待时间,指定的对象处于无信号状态
    112     //           WAIT_ABANDONED:WAIT_ABANDONED_0至(WAIT_ABANDONED_0 + nCount - 1)如果bWaitAll为TRUE,则返回值表明所有指定对象的状态是触发的,并且至少对象之一,是一个废弃的互斥对象。
    113     //         WAIT_FAILED:出现错误,一般是线程句柄错误
    114     //WaitForSingleObject函数,此函数的作用是监视hHandle的状态,当监视的句柄为有信号状态时,即此对象为空闲状态时,此函数返回,才能执行其后的代码。
    115     //WaitForSingleObject(hThread,INFINITE);
    116 
    117     Sleep(1000);
    118     //值得注意的是hThread数组的所有成员必须全部有效,有一个没效的话,次函数就会执行失败
    119     DWORD wm=WaitForMultipleObjects(THREADNUM,hThread,true,10000);
    120     //若果第三个参数是true,则返回值代表所有线程的状态
    121     //若果第三个参数是false,则返回值代表那个有返回线程的状态
    122     switch (wm)
    123     {
    124     case WAIT_FAILED:
    125         printf("wm-->WAIT_FAILED
    ");
    126         break;
    127     case WAIT_TIMEOUT:
    128         printf("wm-->WAIT_TIMEOUT
    ");
    129         break;
    130 
    131     case WAIT_ABANDONED_0+0:
    132     case WAIT_ABANDONED_0+1:
    133     case WAIT_ABANDONED_0+2:
    134         printf("wm-->WAIT_ABANDONED_0
    ");
    135         break;
    136 
    137     case WAIT_OBJECT_0+0:
    138     case WAIT_OBJECT_0+1:
    139     case WAIT_OBJECT_0+2:
    140         printf("wm-->WAIT_OBJECT_0
    ");
    141         break;
    142 
    143     default:
    144         break;
    145     }
    146 
    147     //一般情况下,线程运行结束之后,线程函数正常返回,但是应用程序可以调用TerminateThread强行终止某一线程的执行。
    148     for (int i=0;i<THREADNUM;i++)
    149     {
    150         TerminateThread(hThread[i],0);
    151     }
    152 
    153     // 释放临界区资源,当不再使用临界区时调用该函数  
    154     DeleteCriticalSection(&cs);  
    155     return 0;
    156 }
  • 相关阅读:
    UWP中实现大爆炸效果(二)
    UWP中实现大爆炸效果(一)
    c# 【电影搜索引擎】采集电影站源码
    安利一个聚合搜索导航站,及怎么样设置成默认的搜索引擎
    女朋友经常问影视剧, 答不上来怎么办?
    宝塔linux面板, 服务器日志分析与流量统计这款插件的mysql版优化。
    苹果cms自动采集,重复执行遇到“上次执行时间: --跳过”的解决办法
    苹果cms, 后台设置保存不了的解决办法
    解决 C:WINDOWSsystem32inetsrv ewrite.dll 未能加载。返回的数据为错误.
    img error 图片加载失败的最佳方案
  • 原文地址:https://www.cnblogs.com/xiaocaocao/p/8451851.html
Copyright © 2011-2022 走看看