多线程同步——有序打印数字和字符

问题描述:

创建两个线程,一个线程打印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;
}


多线程同步——有序打印数字和字符_第1张图片

多线程同步——有序打印数字和字符_第2张图片

方法二:临界区

#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,说明应该打印英文字母了。否则就应该打印数字。

你可能感兴趣的:(有趣的编程题,编程学习笔记)