WinApi多线程(CreateThread,CreateMutex,ReleaseMutex)

注:本文写得十分简略.如感到难以理解,请立即参考另一篇写得比我好得多的文章

我们先看一个示例

 1 #include <windows.h>
 2 #include <stdio.h>
 3
 4 DWORD WINAPI reportFunc(LPVOID); // 线程函数的一般原型.可以不返回任何值
 5
 6 #define CntMsg 100
 7
 8 int main()
 9 {
10   /* 建立一个新线程并令其立即执行,返回这个线程的handle
11    * 第三个参数reportFunc代表这个新线程所调用的函数,不同线程可以调用同一个函数
12    * 第四个参数NULL代表传给reportFunc的参数(建议使用指针).传参时会转成void指针,由接收方再转成需要的类型.将会在下个示例程序中用到
13    * 第五个参数0代表立即执行此线程
14    */
15   HANDLE reportHandle = CreateThread(NULL, 0, reportFunc, NULL, 0, NULL);
16   CloseHandle(reportHandle); // 礼节性调用.可有可无
17
18   for (int i = 0; i < CntMsg; ++i) printf("Main Thread: %d\n", i);
19
20   Sleep(1000); // 如果不加这一句,可能会造成主线程报完数并退出后子线程尚未报完数的情况
21 }
22
23 DWORD WINAPI reportFunc(LPVOID para)
24 {
25   for (int i = 0; i < CntMsg; ++i) printf("Report Thread: %d\n", i);
26 }

它的输出大概是这样的(不知道是因为什么,我前两次测试的结果都很奇怪:主线程报完数后子线程才开始报数.这是我第三次测试的结果)

Main Thread: 0
Main Thread: 1
Main Thread: 2
Main Thread: 3
Main Thread: 4
Main Thread: 5
Main Thread: 6
Main Thread: 7
Main Thread: 8
Main Thread: 9
Main Thread: 10
Main Thread: 11
Main Thread: 12
Main Thread: 13
Main Thread: 14
Main Thread: 15
Main Thread: 16
Main Thread: 17
Main Thread: 18
Main Thread: 19
Main Thread: 20
Main Thread: 21
Main Thread: 22
Main Thread: 23
Main Thread: 24
Main Thread: 25
Main Thread: 26
Main Thread: 27
Main Thread: 28
Main Thread: 29
Main Thread: 30
Main Thread: 31
Main Thread: 32
Main Thread: 33
Main Thread: 34
Main Thread: 35
Main Thread: 36
Main Thread: 37
Main Thread: 38
Main Thread: 39
Main Thread: 40
Main Thread: 41
Main Thread: 42
Main Thread: 43
Main Thread: 44
Main Thread: 45
Main Thread: 46
Main Thread: 47
Main Thread: 48
Main Thread: 49
Main Thread: 50
Main Thread: 51
Main Thread: 52
Main Thread: 53
Report Thread: 0
Report Thread: 1
Report Thread: 2
Report Thread: 3
Report Thread: 4
Report Thread: 5
Report Thread: 6
Report Thread: 7
Report Thread: 8
Report Thread: 9
Report Thread: 10
Report Thread: 11
Report Thread: 12
Report Thread: 13
Report Thread: 14
Report Thread: 15
Report Thread: 16
Report Thread: 17
Report Thread: 18
Report Thread: 19
Report Thread: 20
Report Thread: 21
Report Thread: 22
Report Thread: 23
Report Thread: 24
Report Thread: 25
Report Thread: 26
Report Thread: 27
Report Thread: 28
Report Thread: 29
Report Thread: 30
Report Thread: 31
Report Thread: 32
Report Thread: 33
Report Thread: 34
Report Thread: 35
Report Thread: 36
Report Thread: 37
Report Thread: 38
Report Thread: 39
Report Thread: 40
Report Thread: 41
Report Thread: 42
Report Thread: 43
Report Thread: 44
Report Thread: 45
Report Thread: 46
Report Thread: 47
Report Thread: 48
Main Thread: 54
Main Thread: 55
Main Thread: 56
Main Thread: 57
Main Thread: 58
Main Thread: 59
Main Thread: 60
Main Thread: 61
Main Thread: 62
Main Thread: 63
Main Thread: 64
Main Thread: 65
Main Thread: 66
Main Thread: 67
Main Thread: 68
Main Thread: 69
Main Thread: 70
Main Thread: 71
Main Thread: 72
Main Thread: 73
Main Thread: 74
Main Thread: 75
Main Thread: 76
Main Thread: 77
Main Thread: 78
Main Thread: 79
Main Thread: 80
Main Thread: 81
Main Thread: 82
Main Thread: 83
Main Thread: 84
Main Thread: 85
Main Thread: 86
Main Thread: 87
Main Thread: 88
Main Thread: 89
Main Thread: 90
Main Thread: 91
Main Thread: 92
Main Thread: 93
Main Thread: 94
Main Thread: 95
Main Thread: 96
Main Thread: 97
Main Thread: 98
Main Thread: 99
Report Thread: 49
Report Thread: 50
Report Thread: 51
Report Thread: 52
Report Thread: 53
Report Thread: 54
Report Thread: 55
Report Thread: 56
Report Thread: 57
Report Thread: 58
Report Thread: 59
Report Thread: 60
Report Thread: 61
Report Thread: 62
Report Thread: 63
Report Thread: 64
Report Thread: 65
Report Thread: 66
Report Thread: 67
Report Thread: 68
Report Thread: 69
Report Thread: 70
Report Thread: 71
Report Thread: 72
Report Thread: 73
Report Thread: 74
Report Thread: 75
Report Thread: 76
Report Thread: 77
Report Thread: 78
Report Thread: 79
Report Thread: 80
Report Thread: 81
Report Thread: 82
Report Thread: 83
Report Thread: 84
Report Thread: 85
Report Thread: 86
Report Thread: 87
Report Thread: 88
Report Thread: 89
Report Thread: 90
Report Thread: 91
Report Thread: 92
Report Thread: 93
Report Thread: 94
Report Thread: 95
Report Thread: 96
Report Thread: 97
Report Thread: 98
Report Thread: 99

这个程序的功能是建立一个新线程,令其与主线程一起报数

几个线程同时访问同一个变量时,可能会出现一些问题.为了解决这个问题,有人发明了Mutex.这是一个标志,用于判断某个东东是否无法在现在访问(即现在正在被其它线程访问)

下面我们看看第二个示例程序

 1 #include <windows.h>
 2 #include <stdio.h>
 3
 4 int tickets = 100; // 票量
 5 HANDLE ticketMutex; // Mutex的类型是HANDLE
 6
 7 DWORD WINAPI trainStation(LPVOID para)
 8 {
 9   char* stationName = para; // 转类型,接收车站名信息
10
11   while (1)
12   {
13       // 等待Mutex被其它线程释放后,锁定Mutex
14     // 锁定Mutex,相当于告诉其它线程要等待它调用ReleaseMutex后,才能对tickets变量进行操作
15     WaitForSingleObject(ticketMutex, INFINITE);
16
17     if (tickets <= 0) break;
18     printf("%s> %d\n", stationName, --tickets); // 抢票
19
20     // 释放Mutex,告诉其它线程可以开始对tickets变量进行操作了
21     ReleaseMutex(ticketMutex);
22   }
23 }
24
25 #define ARRSIZ(arr) (sizeof(arr) / sizeof(arr[0]))
26
27 int main()
28 {
29   // 使用CreateMutex函数来建立一个Mutex
30   // 其中,最后一个(第三个)参数是一个标识符
31   // 假如需要判断此Mutex是否已被创建,可以写类似CreateMutex(NULL, FALSE, "tickets")之类的代码
32   // 如果另一个标识符为"tickets"的Mutex已被创建,那么ERROR_ALREADY_EXISTS == GetLastError()
33   ticketMutex = CreateMutex(NULL, FALSE, NULL);
34
35   // 车站名
36   char stations[][20] =
37     {
38       "GuangZhou", "BeiJing", "ShangHai",
39       "HuNan", "HeiLongJiang", "XinJiang",
40     };
41
42   // 依次创建代表各省车站的子线程
43   for (int i = 0; i < ARRSIZ(stations); ++i)
44   {
45     CloseHandle(CreateThread(NULL, 0, trainStation, stations[i], 0, NULL));
46   }
47
48   while (1)
49   {
50     WaitForSingleObject(ticketMutex, INFINITE); // 同上
51     if (tickets <= 0) break; // 假如票卖完了,退出程序
52     ReleaseMutex(ticketMutex); // 同上
53   }
54 }

它的输出大概是这样的

GuangZhou> 99
GuangZhou> 98
GuangZhou> 97
GuangZhou> 96
GuangZhou> 95
ShangHai> 94
GuangZhou> 93
ShangHai> 92
GuangZhou> 91
HeiLongJiang> 90
HuNan> 89
ShangHai> 88
BeiJing> 87
XinJiang> 86
GuangZhou> 85
HeiLongJiang> 84
HuNan> 83
ShangHai> 82
BeiJing> 81
XinJiang> 80
GuangZhou> 79
HeiLongJiang> 78
HuNan> 77
ShangHai> 76
BeiJing> 75
XinJiang> 74
GuangZhou> 73
HeiLongJiang> 72
HuNan> 71
ShangHai> 70
BeiJing> 69
XinJiang> 68
GuangZhou> 67
HeiLongJiang> 66
HuNan> 65
ShangHai> 64
BeiJing> 63
XinJiang> 62
GuangZhou> 61
HeiLongJiang> 60
HuNan> 59
ShangHai> 58
BeiJing> 57
XinJiang> 56
GuangZhou> 55
HeiLongJiang> 54
HuNan> 53
ShangHai> 52
BeiJing> 51
XinJiang> 50
GuangZhou> 49
HeiLongJiang> 48
HuNan> 47
ShangHai> 46
BeiJing> 45
XinJiang> 44
GuangZhou> 43
HeiLongJiang> 42
HuNan> 41
ShangHai> 40
BeiJing> 39
XinJiang> 38
GuangZhou> 37
HeiLongJiang> 36
HuNan> 35
ShangHai> 34
BeiJing> 33
XinJiang> 32
GuangZhou> 31
HeiLongJiang> 30
HuNan> 29
ShangHai> 28
BeiJing> 27
XinJiang> 26
GuangZhou> 25
HeiLongJiang> 24
HuNan> 23
ShangHai> 22
BeiJing> 21
XinJiang> 20
GuangZhou> 19
HeiLongJiang> 18
HuNan> 17
ShangHai> 16
BeiJing> 15
XinJiang> 14
GuangZhou> 13
HeiLongJiang> 12
HuNan> 11
ShangHai> 10
BeiJing> 9
XinJiang> 8
GuangZhou> 7
HeiLongJiang> 6
HuNan> 5
ShangHai> 4
BeiJing> 3
XinJiang> 2
GuangZhou> 1
HeiLongJiang> 0

这个程序的功能是模拟火车站的售票系统.各个次线程模拟各个省的火车站,互相竞争100张票,抢到票后输出省份的名称以及剩余的票量.主线程监视票量,在票卖完后停止程序

注意一点:Mutex本身并不知道自己负责管理哪个变量,是否对变量进行操作是完全由程序员来进行的.也就是说,假如某一火车站急需车票,它可以无视Mutex,进行暴力抢票.假如它运气不好,碰上几个线程同时访问同一个变量,就会出现票量异常等情况.假如它运气好,那就当什么事都没有发生,多拿了几张票罢了

你也可以用一个Mutex来完成对多个变量的管理,依个人喜好而定

时间: 2024-08-02 18:58:31

WinApi多线程(CreateThread,CreateMutex,ReleaseMutex)的相关文章

WinAPI多线程

WIN32线程控制主要实现线程的创建.终止.挂起和恢复等操作,这些操作都依赖于WIN32提供的一组API和具体编译器的C运行时库函数.在启动一个线程之前,必须为线程编写一个全局的线程函数,一般来说,C++的类成员函数不能作为线程函数.这是因为在类中定义的成员函数,编译器会给其加上this指针.如果一定要以类成员函数作为线程函数,通常有如下解决方案: (1)将该成员函数声明为static类型,去掉this指针:将成员函数声明为静态虽然可以解决作为线程函数的问题,但是它带来了新的问题,那就是stat

Windows多线程编程总结

Windows 多线程编程总结 keyword:多线程 线程同步 线程池 内核对象 1 内核对象 1 .1 内核对象的概念 内核对象是内核分配的一个内存块,这样的内存块是一个数据结构,表示内核对象的各种特征.而且仅仅能由内核来訪问.应用程序若须要訪问内核对象,须要通过操作系统提供的函数来进行,不能直接訪问内核对象( Windows 从安全性方面来考虑的). 内核对象通过 Create* 来创建,返回一个用于标识内核对象的句柄,这些句柄 (而不是内核对象)可在创建进程范围内使用,不可以被传递到其它

windows多线程(六) 互斥量Mutex与关键段CriticalSection比较

一.关键段CS 和 互斥量Mutex 的相同点:都有线程拥有权 关键段和互斥量都有线程拥有权,即可以被一个线程拥有.在 前面讲关键段CS的文章中有说到,关键段结构体的第四个参数保存着拥有该关键段的线程的句柄,具体如下: typedef struct _RTL_CRITICAL_SECTION { PRTL_CRITICAL_SECTION_DEBUG DebugInfo; // // The following three fields control entering and exiting

20160226.CCPP体系详解(0036天)

程序片段(01):01.多线程.c+02.多线程操作.c 内容概要:多线程 ///01.多线程.c #include <stdio.h> #include <stdlib.h> #include <Windows.h> #include <process.h> //01.线程任务函数剖析: // 1."封装"线程任务代码 // 2.MessageBox();作用: // 用于"阻塞"当前线程的继续执行状态 // 也就是

C++ MFC常用函数(转)

WinExec() ExitWindowsEx() GlobalMemoryStatus() GetSystemInfo() GetSystemDirectory() GetWindowsDirectory() GetTaskmanWindow() //user32.dll中 获取任务栏窗口句柄 OpenProcessToken()打开一个进程的访问令牌 GetCurrentProcess()获取本进程句柄 LookupPrivilegeValue()修改进程权限 AdjustTokenProv

MFC常用函数总结

1.MFC编辑框.静态文本框相关的常用函数 <1>GetDlgItemText(ID ,str) 作用:从对话框中获取文本 第一个参数为要获取的编辑框(或者静态文本框.单选按钮等可以显示内容的控件)的ID,第二个参数为字符串(Cstring 类型)的变量,获取的文本存储在str中. <2>SetDlgItemText(ID,str) 作用:将字符串显示在控件中 第一个参数为要显示的编辑框(或者静态文本框.单选按钮.组合框等可以显示内容的控件)的ID,第二个参数为字符串(Cstrin

delphi.thread.同步

注意:此文只是讲线程间的同步,其它同步不涉及. 线程同步是个好话题,因为写线程经常会遇到,所以就写写自己知道的东西. D里面,同步(特指线程同步)从线程的角度来分,有几种情况: 1:主线程与工作线程的同步 2:工作线程与主线程的同步 3:工作线程之间的同步. 同步,嗯,直白点讲,或可以说成是:A线程怎么通知B线程去做某某事,或者说某事需要:如何控制某一时间段内,A能做,B不能做(互斥). 所以,手段很重要,也就有了API,也就有了方法: 1:lock(CriticalSection) 2:Eve

一步一步学习多线程编程之CreateThread

CreatThread函数如下图所示 在这里我们只用到了第三个和第四个参数,第三个参数传递了一个函数的地址,也是我们要指定的新的线程.第四个参数是传给新线程的参数指针. // ThreadCreateTest.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<windows.h> int time = 0; void ThreadProc1() { int hour = 0; int mins = 0; while(1

秒杀多线程第二篇 多线程第一次亲密接触 CreateThread与_beginthreadex本质区别

版权声明:本文为博主原创文章,未经博主允许不得转载. 本文将带领你与多线程作第一次亲密接触,并深入分析CreateThread与_beginthreadex的本质区别,相信阅读本文后你能轻松的使用多线程并能流畅准确的回答CreateThread与_beginthreadex到底有什么区别,在实际的编程中到底应该使用CreateThread还是_beginthreadex? 使用多线程其实是非常容易的,下面这个程序的主线程会创建了一个子线程并等待其运行完毕,子线程就输出它的线程ID号然后输出一句经