라인 동기화: 귀속 자물쇠, 비귀속 자물쇠

4127 단어
소개
1.1 프로세스/스레드 동기화 방법
흔히 볼 수 있는 프로세스/루틴 동기화 방법에는 상호 배척 자물쇠(또는 상호 배척 Mutex), 읽기 자물쇠(rdlock), 조건 변수(cond), 신호량(Semophore) 등이 있다.
윈도우즈 시스템에서도 임계 영역(Critical Section)과 이벤트 객체(Event)가 자주 사용되는 동기화 방법입니다.
1.2 귀속 잠금/비귀속 잠금
Mutex는 반복 잠금(recursive mutex)과 비반복 잠금(non-recursive mutex)으로 나눌 수 있다.귀속 자물쇠도 다시 들어갈 수 있는 자물쇠(reentrant mutex)라고 하고, 비귀속 자물쇠도 다시 들어갈 수 없는 자물쇠(non-reentrant mutex)라고 한다.
양자의 유일한 차이점은 다음과 같다.
같은 라인에서 같은 귀속 자물쇠를 여러 번 얻을 수 있으며, 고정 자물쇠가 생기지 않는다.
만약 한 라인이 같은 비귀속 자물쇠를 여러 번 얻게 된다면, 사라진 자물쇠가 생길 것이다.
Windows의 Mutex 및 Critical Section은 재귀속적입니다. 
Linux의 pthreadmutex_t 자물쇠는 기본적으로 비귀속적입니다.PTHREADMUTEX_RECURSIVE 속성, pthreadmutex_t 자물쇠를 귀속 자물쇠로 설정합니다.
코드
2.1 Critical Section 폴드 잠금
#include <Windows.h>
#include <iostream>
#include <string>

int counter = 0;

CRITICAL_SECTION g_cs;

void doit(void* arg)
{
	int i, val;
	for (i=0; i<5000; i++)
	{
		EnterCriticalSection(&g_cs);
		EnterCriticalSection(&g_cs);

		val = counter;
		printf("thread %d : %d
", int(arg), val+1); counter = val + 1; LeaveCriticalSection(&g_cs); LeaveCriticalSection(&g_cs); } } int main(int argc, char*argv[]) { InitializeCriticalSection(&g_cs); HANDLE hThread1 = CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)doit, (void*)1, 0, NULL); HANDLE hTrehad2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)doit, (void*)2, 0, NULL); WaitForSingleObject(hThread1, INFINITE); WaitForSingleObject(hTrehad2, INFINITE); DeleteCriticalSection(&g_cs); return 0; }

결과: 자물쇠 1회와 자물쇠 2회를 추가하면 1~10000을 정확하게 출력할 수 있다.
2.2 pthread_mutex_t 비귀속 잠금
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int counter = 0;

pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;

void* doit(void*)
{
        int i, val;
        for (i=0; i<5000; i++)
        {
                pthread_mutex_lock(&g_mutex);
                pthread_mutex_lock(&g_mutex);

                val = counter;
                printf("%x: %d
", pthread_self(), val+1); counter = val + 1; pthread_mutex_unlock(&g_mutex); pthread_mutex_unlock(&g_mutex); } } int main(int argc, char*argv[]) { pthread_t tid1, tid2; pthread_create(&tid1, NULL, doit, NULL); pthread_create(&tid2, NULL, doit, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); return 0; }

결과: 자물쇠를 1회 추가하면 1~10000을 정확하게 출력할 수 있습니다.자물쇠를 2회 추가하고, 자물쇠를 닫으며, 아무런 정보도 출력하지 않습니다.
2.3 pthread_mutex_t 반복 잠금(PTHREAD MUTEX RECURSIVE)
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int counter = 0;

pthread_mutex_t g_mutex;// = PTHREAD_MUTEX_INITIALIZER;

void* doit(void*)
{
        int i, val;
        for (i=0; i<5000; i++)
        {
                pthread_mutex_lock(&g_mutex);
                pthread_mutex_lock(&g_mutex);

                val = counter;
                printf("%x: %d
", pthread_self(), val+1); counter = val + 1; pthread_mutex_unlock(&g_mutex); pthread_mutex_unlock(&g_mutex); } } int main(int argc, char*argv[]) { //create recursive attribute pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); //set recursive attribute pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&g_mutex, &attr); pthread_t tid1, tid2; pthread_create(&tid1, NULL, doit, NULL); pthread_create(&tid2, NULL, doit, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); pthread_mutex_destroy(&g_mutex); //destroy recursive attribute pthread_mutexattr_destroy(&attr); return 0; }
결과: 1회 자물쇠와 2회 자물쇠를 추가하면 모두 1~10000을 정확하게 출력할 수 있다.
참조 자료:http://blog.chinaunix.net/uid-26983585-id-3316794.html

좋은 웹페이지 즐겨찾기