코드 참조
http://tong.nate.com/haru3173/24195740
http://blog.naver.com/gamed21/70015497269

코드 받기



수행 화면
사용자 삽입 이미지
코드 설명
세개의 스레드가 mutex 로 공유된 변수를 접근하는 내용입니다. 장점과 문제점을 동시에 가지고 있는 코드입니다.

코드 내용
/*
	스레드 프로그래밍 연습 - 4 : mutex
	
	mutex_ex.cpp
	저작권
	http://cakel.tistory.com

	참조 코드
	http://tong.nate.com/haru3173/24195740
	http://blog.naver.com/gamed21/70015497269

	교육용을 목적으로 자유롭게 사용하실수 있습니다.
	WIN32 로 만들어진 간단한 mutex 가 사용된 스레드 프로그램입니다.
	
	1번 스레드는 10을 더하는 내용을
	2번 스레드는 5를 빼는 내용을
	3번 스레드는 지정된 검사값을 탐지하는 내용을 갖고 있습니다.
	mutex 의 성질을 십분 활용했습니다. 문제점도 가지고 있습니다.

*/


#include <stdio.h>		// printf()
#include <windows.h>	// Sleep(), HANDLE, CloseHandle(), WaitForSingleObject(), ReleaseHandle()
#include <process.h>	// _beginthread()

// Mutex 용 handle 은 전 스레드에서 쓰기 때문에 중복 선언 하는 거 보다 전역을 빼어
// 썼습니다. 스레드 내에서 쓰셔도 무방합니다. 단 CreateMutex() 함수 수행은
// main 내에서 해야지 디버그하기 용이 합니다.
HANDLE hMutex = 0;

// 이번에 공유할 변수
int nShare = 0;

// 스레드 후보 함수들의 prototype (선선언 하여 이후에 참조해도 문법상 문제가 없게 합니다.
// 문법상 문제가 없더라도 정의를 하지 않는다면 Link 오류가 생깁니다.
void tPlus(void*);		// 덧셈
void tMinus(void*);		// 뺄셈
void tDetect(void*);	// 감지용


int main()
{
	HANDLE hTh1, hTh2, hTh3;
	hMutex = CreateMutex(NULL, FALSE, NULL);

	// 생성된 mutex 가 유효한지 확인합니다.
	if(hMutex == NULL)
	{
		printf("뮤택스 생성 실패 했습니다.\n");
		return 1;

	}

	// 변화 시킬 값입니다. //
	int nPlus = 10;			// tPlus 수행시 증가될 값
	int nMinus = 5;			// nMinus 수행시 감소될 값
	int nDetect = 30;		// 30을 감지 합니다.
	
	// 단계를 밟을 값입니다.
	int i = 0;

	while(i < 10)		// 예상은 총 10회 (0 ~ 9)
	{
		// 스레드를 받아 유효한지 확인도 하고 종료를 기다리게 만들 핸들을 선언합니다.
		hTh1 = (HANDLE) _beginthread(tPlus,0,(void*)&nPlus);
		hTh2 = (HANDLE) _beginthread(tMinus,0,(void*)&nMinus);
		hTh3 = (HANDLE) _beginthread(tDetect,0,(void*)&nDetect);
		
		// 유효성 검토
		if (hTh1 == 0 || hTh2 == 0 || hTh3 == 0)		// 하나라도 불량이면 나가 떨어집니다.
		{
			printf("스레드 생성 오류 입니다.\n");
			return 1;
		}

//		hTh3 만 막아 줘야지 만약 그렇지 않고 계산 중의 수를 변화 탐지 할수가 없을수 있습니다.
//		hTh3 가 수행되기 전에 먼저 hTh1 과 hTh2 가 먼저 계산이 될수 있기 때문입니다.
	
//		WaitForSingleObject(hTh1, INFINITE);		
//		WaitForSingleObject(hTh2, INFINITE);
		WaitForSingleObject(hTh3, INFINITE);


		i++;	// 스레드의 수행이 끝나면 한단계를 증가 합니다.

	}

	// 마지막으로 열어둔 핸들을 닫습니다.
	CloseHandle(hTh1);
	CloseHandle(hTh2);
	CloseHandle(hTh3);
	CloseHandle(hMutex);

	return 0;

}


void tPlus(void *pData)
{
	// void 포인터로 받으면 받을 값을 미리 알아 둬야 할 불편함이 있습니다.
	// 형변환을 해야 하니깐요.

	// Mutex 핸들을 활성화 하여 전역 변수를 단일 스레드만 접근할수 있게 합니다.
	// WAIT_FAILED 는 WaitForSingleObject() 함수 수행 결과가 실패 했으면 스레드가 정상
	// 수행 되지 않기 때문에 안전 장치로 추가했습니다.

	if(WaitForSingleObject(hMutex, INFINITE) == WAIT_FAILED)
	{
		printf("스레드 Wait 오류\n 스레드 종료\n");
		return;

	}

	// Dereference 값 참조 (void* -> int*) int 형 주소로 void 형 주소를 강제
	// 변환한후 값을 가져 오는 방식입니다. 바로 void* 를 값 참조 할수 없습니다.
	nShare += *(int*)pData;
	printf("스레드 1 : Plus 계산후 nShare, : %d\n", nShare);

	// Sleep() 을 ReleaseMutex 밖에서 하니깐 문제가 발생했습니다.
	// hMutex 를 전역위치에서 CreateMutex() 쓰니깐 Sleep() 에서 문제가 발생했습니다.
	// 작동을 하지 않았습니다.
	Sleep(1000);

	// Mutex 를 풀어서 전역 변수의 독점을 해제 합니다.
	ReleaseMutex(hMutex);


}

void tMinus(void *pData)
{
	// tPlus 함수와 크게 다르지 않습니다.
	if(WaitForSingleObject(hMutex, INFINITE) == WAIT_FAILED)
	{
		printf("스레드 Wait 오류\n 스레드 종료\n");
		return;

	}
	nShare -= *(int*)pData;
	printf("스레드 2 : Minus 계산후 nShare : %d\n", nShare);
	// Mutex 를 풀어서 전역 변수의 독점을 해제 합니다.
	Sleep(200);
	ReleaseMutex(hMutex);
	


}

void tDetect(void *nDetect)
{
	// tDetect 비교
	if(WaitForSingleObject(hMutex, INFINITE) == WAIT_FAILED)
	{
		printf("스레드 Wait 오류\n 스레드 종료\n");
		return;

	}
	
	printf("스레드 3 : 검사 - %d == %d\n", *(int*)nDetect, nShare);
	if (nShare == *(int*)nDetect)
	{	// Mutex 의 한계로 덧셈 뺄샘 한 결과가 저장된 nShare 값을 탐지하므로 값이 실시간으로 잡지 못합니다.
		printf("%d 이 검사값과 일치\n", *(int*)nDetect);

	}

	// Mutex 를 풀어서 전역 변수의 독점을 해제 합니다.
	ReleaseMutex(hMutex);
	return;


}
Posted by 카켈