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线程已经工作了\n",tNum); 25 26 if (1) 27 { 28 //临界区 29 EnterCriticalSection(&cs);// 进入临界区,其它线程则无法进入 30 //ccs.Lock(); 31 // 安全访问该区域 32 gInt--; 33 printf("第%d线程检测到全局变量gInt的值是:%d\n",tNum,gInt); 34 Sleep(0);//致使不使用临界区肯定出错的方法 35 gInt++; 36 printf("第%d线程检测到全局变量gInt的值是:%d\n",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\n",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时候出错了\n"); 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\n"); 126 break; 127 case WAIT_TIMEOUT: 128 printf("wm-->WAIT_TIMEOUT\n"); 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\n"); 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\n"); 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 }