学习基于WINAPI的多线程开发

下面是我对Windows平台上的多线程开发的一些理解,具体的可以看代码:

0 线程直接相关的函数是:

  • ResumeThread;
  • SuspendThread;
  • TerminateThread;

1 互斥控制是用互斥锁:Mutex

  • CreateMutex;
  • OpenMutex;
  • ReleaseMutex;

2 同步控制是用信号量:Semaphore

  • CreateSemaphore;
  • OpenSemaphore;
  • ReleaseSemaphore;

3 互斥也是一种同步,即同步包含互斥,据说还有一个专门用来表示互斥的结构体,目前没有用过。

4 创建线程的时候可以传参,一定要注意保护参数。

5 多线程并发时的输入输出注意保护其互斥性,避免输出混乱。

6 对线程传参如果参数复杂的话,最好提前定义一个数据结构,下面我的代码中并没有去定义一个很好的数据结构。

7 对线程传参时,要把信号量名字传过去,或者定义成全局变量,最好,是采用6的方案

8 除了常用的WaitForSingleObject,还有WaitForMultipleObjects,不过后者目前我还没有用过。

9 以上提到的函数是在控制台程序和WIN32窗口程序中用的,而在MFC中,另有线程类CWinThread和信号量类CSemaphore等等。

10 进程/线程同步有四种方法:

  1. 临界区,只能用于进程内部的线程之间同步
    1. CRITICAL_SECTION cs; //临界区结构体
    2. InitializeCriticalSection(&cs); //初始化临界区
    3. EnterCriticalSection(&cs); //进入临界区
    4. LeaveCriticalSection(&cs); //离开临界区
    5. DeleteCriticalSection(&cs); //删除临界区
  2. event,可以用于进程间同步
  3. mutex,可以用于进程间同步
  4. semaphore,可以用于进程间同步

代码:

  1 #include <windows.h>
  2 #include <time.h>
  3 #include <iostream>
  4 #include <assert.h>
  5 
  6 /**
  7 * @author:zanzan101
  8 */
  9 
 10 using namespace std;
 11 
 12 #define MAX 20
 13 
 14 void thinking(char para, HANDLE mutex)
 15 {
 16     // 这里需要互斥,不然都打印混了
 17     WaitForSingleObject(mutex, INFINITE);
 18     cout<< para << " is thinking ..." << endl;
 19     ReleaseMutex(mutex);
 20     Sleep(rand()%100);
 21 }
 22 
 23 void eating(char para, HANDLE mutex)
 24 {
 25     // 这里需要互斥,不然都打印混了
 26     WaitForSingleObject(mutex, INFINITE);
 27     cout<< para << " is eating ..." << endl;
 28     ReleaseMutex(mutex);
 29     Sleep(rand()%1000);
 30 }
 31 
 32 DWORD __stdcall philosopher(void* para)
 33 {
 34     // 注:Open系列的函数,如果第一个参数是0,则创建出来的都是NULL
 35     char ch;
 36     char print_mutex_name[] = "print_mutex";
 37     HANDLE hPrintMutex = OpenMutex(MUTEX_ALL_ACCESS, 0, print_mutex_name);
 38 
 39     char chopstick_semaphore_name[] = "chopstick_semaphore";
 40     HANDLE hCountSemaphore = OpenSemaphore(SEMAPHORE_ALL_ACCESS, 0, chopstick_semaphore_name);
 41 
 42     char chopstick_mutex_name[] = "X_chopstick";
 43     chopstick_mutex_name[0] = *(char*)para;
 44     HANDLE hChopstick1 = OpenMutex(MUTEX_ALL_ACCESS, 0, chopstick_mutex_name);
 45     chopstick_mutex_name[0] = (*(char*)para-'A'+1)%MAX + 'A';
 46     HANDLE hChopstick2 = OpenMutex(MUTEX_ALL_ACCESS, 0, chopstick_mutex_name);
 47 
 48 
 49     // 这里测试输出了子线程栈的起始地址,发现子线程的起始地址按照设定的大小逐倍向高地址增长
 50     // 即后面的线程的栈起始地址,比前面线程栈的起始地址的差距,为创建线程时设定的栈大小
 51      WaitForSingleObject(hPrintMutex, INFINITE);
 52      cout << *(char*)para << "\'s stack size is " << ((unsigned int(&ch))>>10) << " KB" << endl;
 53      ReleaseMutex(hPrintMutex);
 54 
 55     while(1)
 56     {
 57         thinking(*(char*)para, hPrintMutex);
 58 
 59         WaitForSingleObject(hPrintMutex, INFINITE);
 60         cout << *(char*)para << " end thinking ..." << endl;
 61         ReleaseMutex(hPrintMutex);
 62 
 63         // 打破死锁的方法之一
 64         // 限制同时吃饭的人数
 65         // 当一共有N个人时,我们限制最多同时有N-1个人请求持筷子,这样必然打破环路等待条件
 66 #if 1
 67         WaitForSingleObject(hCountSemaphore, INFINITE);
 68 #endif
 69 
 70         WaitForSingleObject(hChopstick1, INFINITE);
 71 
 72         WaitForSingleObject(hPrintMutex, INFINITE);
 73         cout << *(char*)para << " get first chopstick ..." << endl;
 74         ReleaseMutex(hPrintMutex);
 75 
 76         // 为了测试死锁,故意增大拿两个筷子的间隔,以提高死锁的概率。
 77         Sleep(rand()%1000);
 78         WaitForSingleObject(hChopstick2, INFINITE);
 79 
 80         WaitForSingleObject(hPrintMutex, INFINITE);
 81         cout << *(char*)para << " get second chopstick ..." << endl;
 82         ReleaseMutex(hPrintMutex);
 83 
 84 #if 1
 85         ReleaseSemaphore(hCountSemaphore, 1, NULL);
 86 #endif
 87 
 88         eating(*(char*)para, hPrintMutex);
 89 
 90         WaitForSingleObject(hPrintMutex, INFINITE);
 91         cout << *(char*)para << " end eating ..." << endl;
 92         ReleaseMutex(hPrintMutex);
 93 
 94         ReleaseMutex(hChopstick1);
 95         ReleaseMutex(hChopstick2);
 96 
 97         WaitForSingleObject(hPrintMutex, INFINITE);
 98         cout << *(char*)para << " put down chopsticks ..." << endl;
 99         ReleaseMutex(hPrintMutex);
100     }
101 }
102 
103 int main()
104 {
105     assert(MAX <= 26);
106     char ch;
107 
108     char str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
109     HANDLE hMutex[MAX];
110     HANDLE hPrintMutex;
111     HANDLE hCountSemaphore;
112     char chopstick_mutex_name[] = "X_chopstick";
113     for (int i = 0; i < MAX; i++)
114     {
115         chopstick_mutex_name[0] = str[i];
116         
117         // 创建筷子的互斥锁
118         hMutex[i] = CreateMutex(0, NULL, chopstick_mutex_name);
119     }
120     hPrintMutex = CreateMutex(0, NULL, "print_mutex");
121     hCountSemaphore = CreateSemaphore(NULL, 4, 4, "chopstick_semaphore");
122     HANDLE philosophers[MAX];
123     int count = MAX;
124     srand(time(0));
125 
126     WaitForSingleObject(hPrintMutex, INFINITE);
127     cout << "main's stack size is " << (unsigned int(&ch))/1024 << " KB" << endl;
128     ReleaseMutex(hPrintMutex);
129 
130     for(int i = 0; i < MAX; i++)
131     {
132         // 创建线程
133         // 线程栈大小设置为1K
134         // 要尽量保证在传址之后,在该线程的生命周期中,不去改变该地址的数据,以免多线程并发时出现意外
135         // 这里我对每个线程传参不同,而且后面不再修改这个地址,做到了上面这一点
136         philosophers[i] = CreateThread(NULL, 1>>10, philosopher, (void*)&str[i], 0, NULL);
137     }
138 
139     Sleep(2000);
140 
141     // 如果不挂起子线程,主线程暂停时,子线程继续运行,不受任何影响
142     // 因此,这里需要挂起子线程,暂停子线程
143     for(int i = 0; i < count; i++)
144         SuspendThread(philosophers[i]);
145     system("pause");
146 
147 //  下面这里,如果终止的线程,后面就无法再次启动线程了,因此这里不能终止线程
148 //     for(int i = 0; i < count; i++)
149 //         TerminateThread(philosophers[i], 0);
150 
151     // 再次启动线程
152     for(int i = 0; i < count; i++)
153         ResumeThread(philosophers[i]);
154 
155     Sleep(2000);
156     // 再次挂起线程
157     for(int i = 0; i < count; i++)
158         SuspendThread(philosophers[i]);
159 
160     system("pause");
161 
162     // 终止线程
163     for(int i = 0; i < count; i++)
164         TerminateThread(philosophers[i], 0);
165     // 关闭句柄
166     for(int i = 0; i < count; i++)
167         CloseHandle(philosophers[i]);
168     return 0;
169 }

输出结果:

main's stack size is 1215 KB
A's stack size is 5247 KB
B's stack size is 6271 KB
D's stack size is 8319 KB
F's stack size is 10367 KB
J's stack size is 14463 KB
C's stack size is 7295 KB
E's stack size is 9343 KB
G's stack size is 11391 KB
I's stack size is 13439 KB
K's stack size is 15487 KB
M's stack size is 17535 KB
S's stack size is 23679 KB
R's stack size is 22655 KB
P's stack size is 20607 KB
Q's stack size is 21631 KB
N's stack size is 18559 KB
O's stack size is 19583 KB
H's stack size is 12415 KB
T's stack size is 24703 KB
L's stack size is 16511 KB
A is thinking ...
B is thinking ...
D is thinking ...
F is thinking ...
J is thinking ...
C is thinking ...
E is thinking ...
G is thinking ...
I is thinking ...
K is thinking ...
M is thinking ...
S is thinking ...
R is thinking ...
P is thinking ...
Q is thinking ...
N is thinking ...
O is thinking ...
H is thinking ...
T is thinking ...
L is thinking ...
A end thinking ...
A get first chopstick ...
B end thinking ...
D end thinking ...
F end thinking ...
B get first chopstick ...
J end thinking ...
D get first chopstick ...
C end thinking ...
F get first chopstick ...
E end thinking ...
G end thinking ...
I end thinking ...
K end thinking ...
M end thinking ...
S end thinking ...
R end thinking ...
P end thinking ...
Q end thinking ...
N end thinking ...
O end thinking ...
H end thinking ...
T end thinking ...
L end thinking ...
B get second chopstick ...
B is eating ...
J get first chopstick ...
D get second chopstick ...
F get second chopstick ...
D is eating ...
F is eating ...
B end eating ...
B put down chopsticks ...
A get second chopstick ...
C get first chopstick ...
B is thinking ...
A is eating ...
D end eating ...
F end eating ...
B end thinking ...
D put down chopsticks ...
E get first chopstick ...
F put down chopsticks ...
G get first chopstick ...
D is thinking ...
F is thinking ...
D end thinking ...
F end thinking ...
J get second chopstick ...
J is eating ...
I get first chopstick ...
A end eating ...
A put down chopsticks ...
A is thinking ...
A end thinking ...
J end eating ...
J put down chopsticks ...
J is thinking ...
C get second chopstick ...
J end thinking ...
C is eating ...
K get first chopstick ...
E get second chopstick ...
E is eating ...
M get first chopstick ...
G get second chopstick ...
G is eating ...
S get first chopstick ...
I get second chopstick ...
I is eating ...
R get first chopstick ...
C end eating ...
C put down chopsticks ...
C is thinking ...
C end thinking ...
E end eating ...
E put down chopsticks ...
E is thinking ...
E end thinking ...
G end eating ...
G put down chopsticks ...
G is thinking ...
G end thinking ...
I end eating ...
I put down chopsticks ...
I is thinking ...
I end thinking ...
K get second chopstick ...
K is eating ...
P get first chopstick ...
M get second chopstick ...
M is eating ...
Q get first chopstick ...
S get second chopstick ...
S is eating ...
请按任意键继续. . .
K end eating ...
M end eating ...
S end eating ...
K put down chopsticks ...
M put down chopsticks ...
N get first chopstick ...
S put down chopsticks ...
R get second chopstick ...
K is thinking ...
M is thinking ...
S is thinking ...
R is eating ...
A get first chopstick ...
K end thinking ...
M end thinking ...
S end thinking ...
A get second chopstick ...
A is eating ...
R end eating ...
R put down chopsticks ...
Q get second chopstick ...
R is thinking ...
Q is eating ...
C get first chopstick ...
R end thinking ...
N get second chopstick ...
N is eating ...
D get first chopstick ...
D get second chopstick ...
D is eating ...
Q end eating ...
Q put down chopsticks ...
P get second chopstick ...
Q is thinking ...
P is eating ...
F get first chopstick ...
Q end thinking ...
N end eating ...
N put down chopsticks ...
N is thinking ...
N end thinking ...
F get second chopstick ...
F is eating ...
A end eating ...
A put down chopsticks ...
B get first chopstick ...
A is thinking ...
A end thinking ...
P end eating ...
P put down chopsticks ...
P is thinking ...
P end thinking ...
D end eating ...
D put down chopsticks ...
C get second chopstick ...
E get first chopstick ...
D is thinking ...
C is eating ...
H get first chopstick ...
D end thinking ...
F end eating ...
F put down chopsticks ...
E get second chopstick ...
G get first chopstick ...
F is thinking ...
E is eating ...
I get first chopstick ...
F end thinking ...
I get second chopstick ...
I is eating ...
请按任意键继续. . .

 

转载于:https://www.cnblogs.com/zanzan101/p/3372659.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值