问题描述:
创建两个线程,一个线程打印1,2,3,……,52,另一个线程打印A,B,C,……,Z。要求打印出来的效果为:
1
2
A
3
4
B
……
51
52
Z
交替有序进行。
多线程同步在很多时候有不止一种方法实现。比如这道题既可以用线程间通信,也可以用临界区,都可以达到同样的效果。
方法一:线程间通信
线程1每次打印2个数字,线程2每次打印1个字母。线程1打印完后,通知线程2,并阻塞等待线程2的通知。线程2打印完后,通知线程1,并阻塞等待线程1的通知......直到打印完成。
#include
#include
using namespace std;
DWORD WINAPI printNumbers(LPVOID param);
DWORD WINAPI printCharacters(LPVOID param);
//需要用户自己定义消息的ID
//这个ID必须要大于WM_USER,小于WM_USER的已经被系统占用
#define MY_MSG (WM_USER+1)
//打印的数字和字母
int number = 1;
char ch = 'A';
int main()
{
//先获取两个线程的ID
DWORD threadID1 = 0, threadID2 = 0;
//线程1打印数字
HANDLE hThread1 = CreateThread(NULL, 0, printNumbers, (LPVOID)&threadID2, 0, &threadID1);
//线程2打印英文字母
HANDLE hThread2 = CreateThread(NULL, 0, printCharacters, (LPVOID)&threadID1, 0, &threadID2);
HANDLE hArr[] = { hThread1 ,hThread2 };
WaitForMultipleObjects(2, hArr, TRUE, INFINITE);
return 0;
}
DWORD WINAPI printNumbers(LPVOID param) {
Sleep(200);//等待一小会,让线程2得以创建
//传入的参数是线程2的ID的地址
DWORD threadID2 = *(DWORD*)param;
MSG msg;//建立一个消息结构体
do{
printf("%d\n", number++);
printf("%d\n", number++);
if (number < 53) {
//给线程2发消息,我已经打印了两个数字
//消息的内容不重要,就发NULL吧
PostThreadMessage(threadID2, MY_MSG, NULL, NULL);
}
else {
//因为是线程1先打印完,线程1给线程2发WM_QUIT
PostThreadMessage(threadID2, WM_QUIT, NULL, NULL);
break;
}
} while (GetMessage(&msg, NULL, 0, 0) && msg.message == MY_MSG);
return 0;
}
DWORD WINAPI printCharacters(LPVOID param) {
Sleep(200);//等待一小会,让线程1得以创建
//传入的参数是线程1的ID的地址
DWORD threadID1 = *(DWORD*)param;
MSG msg;//建立一个消息结构体
while (GetMessage(&msg, NULL, 0, 0) && msg.message == MY_MSG) {
//打印一个英文字母
printf("%c\n", ch++);
//给线程1发消息,我已经打印了一个英文字母
//消息的内容不重要,就发NULL吧
PostThreadMessage(threadID1, MY_MSG, NULL, NULL);
}
//GetMessage收到线程1发来的WM_QUIT后,返回false,退出循环
//注意,这时候Z还没被打印,所以还要打印Z
printf("%c\n", ch);
return 0;
}
方法二:临界区
#include
#include
using namespace std;
DWORD WINAPI printNumbers(LPVOID param);
DWORD WINAPI printCharacters(LPVOID param);
//临界区变量
CRITICAL_SECTION cs;
//打印的数字和字母
int number = 1;
char ch = 'A';
//用来控制打印出来的内容的变量
int counted = 1;
int main()
{
//初始化临界区变量
InitializeCriticalSection(&cs);
//线程1打印数字
HANDLE hThread1 = CreateThread(NULL, 0, printNumbers, NULL, 0, 0);
//线程2打印英文字母
HANDLE hThread2 = CreateThread(NULL, 0, printCharacters, NULL, 0, 0);
HANDLE hArr[] = { hThread1 ,hThread2 };
WaitForMultipleObjects(2, hArr, TRUE, INFINITE);
return 0;
}
DWORD WINAPI printNumbers(LPVOID param) {
while (true) {
EnterCriticalSection(&cs);
if (counted % 3 != 0) {
printf("%d\n", number++);
counted++;
printf("%d\n", number++);
counted++;
}
LeaveCriticalSection(&cs);
if (counted >= 78) break;
}
return 0;
}
DWORD WINAPI printCharacters(LPVOID param) {
while (true) {
EnterCriticalSection(&cs);
if (counted % 3 == 0) {
printf("%c\n", ch++);
counted++;
}
LeaveCriticalSection(&cs);
if (counted >= 78) break;
}
return 0;
}
用一个变量counted来控制打印出来的内容。每打印出一个数字或字符,counted++。如果counted%3==0,说明应该打印英文字母了。否则就应该打印数字。