SPAN class=postbody메모리의 Bus lock을 lock이라는 어셈블리 명령어를 사용하여 br /C언어만으로는 만들수 없는 Lock을 구현한것입니다. br /br /이 소스는 SMP에서도 잘 돌아갈것입니다. br /이유는 Memory의 bus를 lock하는 것이기 때문에 가능한 것입니다. br /br /x86계열 호환입니다. 코드는 VC++ 또는 gcc 로 컴파일 가능합니다. br /br /*** 예외상황 정리 *** br /1. lock상호간의 race condition(경쟁조건) br /만약 A,B 두개의 lock 키를 다룬다고 하죠. br /그리고 (a), (b) 두개의 thread가 움직입니다. br /이때 (a)에서는 Lock(A)-gt;Lock(B)-gt;Unlock(B)-gt;Unlock(A) 순으로 lock을 걸겠습니다. br /그런데 (b)에서는 Lock(B)-gt;Lock(A)-gt;Unlock(A)-gt;Unlock(B)로 lock을 건다고 br /상황을 만들어보세요. br /과연 이 두개의 thread는 완전히 race condition을 극복할수 있다고 생각하십니까? br /br /2. Dead lock (헤어나지 못하는 조건) br /Lock(A)-gt;Lock(A)-gt;Unlock(A)-gt;Unlock(A) 이런 상황은 당연히 벗어날수 없는 br /무한 lock상태에 돌입한다는 것은 누구나 쉽게 떠오를것입니다. br /하지만 코딩하다보면 심심치 않게 버그로 남는 상황이 이러한 것입니다. br /br /3. Kernel의 특권 ! 불가피한 dead lock 회피 br /CLI-gt;STI만으로 CPU가 몇백개가 병별로 처리되더라도 벗어날수 있는 특권! br /하지만 잘 안사용하겠죠? br /성능저하가 상상초월. br /하지만 CLI-gt;do{ ...-gt;SLEEP ON-gt;... }while(isok)-gt;STI는 좀 낮겠군요. br /의도는 아시겠죠? 비선점형에서 선점형으로 진입하는... br /br //SPAN
TABLE cellSpacing=1 cellPadding=3 width=90% align=center border=0
TBODY
TR
TDSPAN class=genmedB코드:/B/SPAN/TD/TR
TR
TD class=codebr //* br /Code by JaeHyuk Cho lt;mailto:minzkn@infoeq.comgt; Made in KOREA br /http://minzkn.pe.ky br /*/ br /br /#ifndef DEF_SOURCE_lock_c br /#define DEF_SOURCE_lock_c lock.c br /br /#include lt;stdio.hgt; br /#include lt;sched.hgt; br /br /#define __DEF_FCTYPE__ br /br /static int __DEF_FCTYPE__ __MZ_Lock__(int * volatile s_LockFlag, int s_Switch); br /static int __DEF_FCTYPE__ __MZ_AtomicExchange__(int * volatile s_To, int s_Value); br /br /int MZ_InitLock(int * volatile s_Key); br /void MZ_Lock(int * volatile s_Key); br /void MZ_UnLock(int * volatile s_Key); br /br /static int __DEF_FCTYPE__ __MZ_Lock__(int * volatile s_LockFlag, int s_Switch) br /{ br /int s_Return; br /int s_LockTime = 0, s_TimeOut; br /s_TimeOut = (s_Switch gt;gt; 2) * 100; br /L_SpinLoop:; br /s_Return = __MZ_AtomicExchange__(s_LockFlag, s_Switch); br /if(s_Switch != 0 amp;amp; s_Return != 0) br /{ br /nbsp; if(s_TimeOut != 0 amp;amp; s_LockTime gt; s_TimeOut) br /nbsp; { br /nbsp; nbsp;fprintf(stderr, %s: %s - [ERROR] Dead-lock instead of off (%d second timeout) !!!\n, __FILE__, __FUNCTION__, s_TimeOut * br /100); br /nbsp; nbsp;s_Return = __MZ_AtomicExchange__(s_LockFlag, 0); br /nbsp; } br /nbsp; else br /nbsp; { br /nbsp; nbsp;sched_yield(); br /nbsp; nbsp;s_LockTime++; br /nbsp; nbsp;goto L_SpinLoop; br /nbsp; } br /} br /return(s_Return); br /} br /br /static int __DEF_FCTYPE__ __MZ_AtomicExchange__(int * volatile s_To, int s_Value) br /{ br /register int s_Return; br /#ifdef WIN32 br /MZ_ASM br /{ br /nbsp; PUSH EBX; br /nbsp; MOV EAX, s_Value; br /nbsp; MOV EBX, s_To; br /nbsp; LOCK XCHG DWORD PTR [EBX], EAX; br /nbsp; POP EBX; br /} br /#else br /MZ_ASM( br /nbsp; \n\t br /nbsp; lock xchgl %1, (%2)\n\t br /nbsp; \n\t br /nbsp; : =a(s_Return) br /nbsp; : a(s_Value), r(s_To) br /); br /#endif br /return(s_Return); br /} br /br /int MZ_InitLock(int * volatile s_Key) br /{ br /if(s_Key)MZ_UnLock(s_Key); br /return(0); br /} br /br /void MZ_Lock(int * volatile s_Key) br /{ br /(void)__MZ_Lock__(s_Key, 1); br /} br /br /void MZ_UnLock(int * volatile s_Key) br /{ br /(void)__MZ_Lock__(s_Key, 0); br /} br /#endif br /br //* End of source */ br //TD/TR/TBODY/TABLEbr /br /br /
TABLE cellSpacing=1 cellPadding=3 width=90% align=center border=0
TBODY
TR
TDSPAN class=genmedB코드:/B/SPAN/TD/TR
TR
TD class=code/* br /nbsp; Copyright (C) Information Equipment co.,LTD br /nbsp; All rights reserved. br /nbsp; Code by JaeHyuk Cho lt;mailto:minzkn@infoeq.comgt; br /nbsp; CVSTAG=$Header$ br /*/ br /br /#include lt;sys/types.hgt; br /#include lt;sys/time.hgt; br /#include lt;stdio.hgt; br /#include lt;stdlib.hgt; br /#include lt;string.hgt; br /#include lt;unistd.hgt; br /#include lt;signal.hgt; br /#include lt;sched.hgt; br /br /#include lt;pthread.hgt; br /br /#define def_test_threads (8) br /#define def_use_lock (1) br /br /#if defined(__i386__) || defined(_M_IX86) br /# define __def_mz_i386__ br /#endif br /#if defined(__powerpc__) || defined(_M_PPC) br /# define __def_mz_ppc__ br /#endif br /#if defined(__mips__) || defined(_M_MRX000) br /# define __def_mz_mips__ br /#endif br /br /static char g_mz_architecture[ 1 lt;lt; 10 ] = {not defined}; br /static int g_mz_ctrl_break = 0; br /int g_mz_lock = 0; br /br /int (mz_atomic_exchange)(int * volatile s_to, int s_value) br /{ br /#if defined(__def_mz_i386__) br /nbsp;(void)strcpy((char *)(amp;g_mz_architecture[0]), i386); br /nbsp;__asm__ __volatile__(xchgl (%2), %0\n\t : =r(s_value) : 0(s_value), r(s_to)); br /nbsp;return(s_value); br /#elif defined(__def_mz_ppc__) br /nbsp;int s_temp; br /nbsp;(void)strcpy((char *)(amp;g_mz_architecture[0]), ppc); br /nbsp;__asm__ __volatile__( br /nbsp; 0:\n\t br /nbsp; lwarx %0,0,%1\n\t br /nbsp; stwcx. %2,0,%1\n\t br /nbsp; bne- 0b\n\t br /nbsp; : =amp;r(s_temp) br /nbsp; : r(s_to),r(s_value) br /nbsp; : cr0, memory br /nbsp;); br /nbsp;return(s_temp); br /#elif defined(__def_mz_arm__) /* not tested */ br /nbsp;int s_temp; br /nbsp;(void)strcpy((char *)(amp;g_mz_architecture[0]), arm); br /nbsp;__asm__ __volatile__( br /nbsp; swp %0, %1, [%2] br /nbsp; : =r(s_value) br /nbsp; : 0(s_value), r(s_to) br /nbsp; : memory br /nbsp;); br /nbsp;return(s_temp); br /#elif defined(__def_mz_mips__) br /nbsp;int s_result, s_temp; br /nbsp;(void)strcpy((char *)(amp;g_mz_architecture[0]), mips); br /nbsp;__asm__ __volatile__( br /nbsp; 1:\n\t br /nbsp; .set push\n\t br /nbsp; .set mips2\n\t br /nbsp; ll %0,%3\n\t br /nbsp; move %1,%4\n\t br /nbsp; beq %0,%4,2f\n\t br /nbsp; sc %1,%2\n\t br /nbsp; .set pop\n\t br /nbsp; beqz %1,1b\n br /nbsp; 2:\n\t br /nbsp; : =amp;r (s_result), =amp;r (s_temp), =m (*s_to) br /nbsp; : m (*s_to), r (s_value) br /nbsp; : memory); br /nbsp;return(s_result); br /#else /* unknown architecture */ br /nbsp;static pthread_mutex_t sg_mz_mutex_bus = PTHREAD_MUTEX_INITIALIZER; br /nbsp;int s_temp, s_check; br /nbsp;(void)strcpy((char *)(amp;g_mz_architecture[0]), unknown); br /nbsp;pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, (void *)(amp;sg_mz_mutex_bus)); br /nbsp;s_check = pthread_mutex_lock((pthread_mutex_t *)(amp;sg_mz_mutex_bus)); br /nbsp;s_temp = *(s_to); *(s_to) = s_value; br /nbsp;s_check = pthread_mutex_unlock((pthread_mutex_t *)(amp;sg_mz_mutex_bus)); br /nbsp;pthread_cleanup_pop(0); br /nbsp;return(s_temp); br /#endif br /} br /br /void (mz_load_balance)(void) br /{ br /nbsp;sched_yield(); br /} br /br /void (mz_unlock)(int *s_this) br /{ br /nbsp;(void)mz_atomic_exchange(s_this, 0); br /} br /br /void (mz_lock)(int *s_this) br /{ br /nbsp;l_lock_wait:; br /nbsp;if(mz_atomic_exchange(s_this, 1) == 0)return; br /nbsp;mz_load_balance(); br /nbsp;goto l_lock_wait; br /} br /br /void (mz_signal)(int s_signal) br /{ br /nbsp;switch(s_signal) br /nbsp;{ br /nbsp; case SIGINT: case SIGTERM: br /nbsp; nbsp; nbsp; nbsp;if(g_mz_ctrl_break == 0)(void)fputs(\nbreak.\x1b[0m\n, stdout); br /nbsp; nbsp; nbsp; nbsp;g_mz_ctrl_break = 1; br /nbsp; nbsp; nbsp; nbsp;(void)signal(s_signal, mz_signal); br /nbsp; nbsp; nbsp; nbsp;break; br /nbsp; case SIGSEGV: case SIGFPE: br /nbsp; nbsp; nbsp; nbsp;g_mz_ctrl_break = 1; br /nbsp; nbsp; nbsp; nbsp;(void)fputs(\nOOPS: segment fault\x1b[0m\n, stderr); br /nbsp; nbsp; nbsp; nbsp;(void)raise(s_signal); br /nbsp; nbsp; nbsp; nbsp;exit(0); br /nbsp; default: break; br /nbsp;} br /} br /br /void * (mz_test_thread)(void *s_argument) br /{ br /nbsp;int s_pid = (int)getpid(); br /nbsp;(void)fprintf(stdout, run thread %d\n, s_pid); br /nbsp;do br /nbsp;{ br /#if def_use_lock != (0) br /nbsp; mz_lock((int *)(amp;g_mz_lock)); br /#endif br /nbsp; *((int *)s_argument) = 0; br /nbsp; mz_load_balance(); br /nbsp; *((int *)s_argument) = s_pid; br /#if def_use_lock != (0) br /nbsp; mz_unlock((int *)(amp;g_mz_lock)); br /#endif br /nbsp; mz_load_balance(); br /nbsp;}while(g_mz_ctrl_break == 0);nbsp; nbsp; nbsp; nbsp; br /nbsp;return(s_argument); br /} br /br /int (main)(void) br /{ br /nbsp;pthread_t s_pthread[ def_test_threads ]; br /nbsp;int s_index; br /nbsp;volatile int s_test_value = (int)getpid(); br /nbsp;(void)signal(SIGINT, mz_signal); br /nbsp;(void)signal(SIGTERM, mz_signal); br /nbsp;(void)signal(SIGSEGV, mz_signal); br /nbsp;(void)signal(SIGFPE, mz_signal); br /nbsp;(void)mz_atomic_exchange((int *)(amp;g_mz_lock), 0); br /nbsp;(void)fprintf(stdout, architecture=%s\n, (char *)(amp;g_mz_architecture[0])); br /nbsp;for(s_index = 0;s_index lt; def_test_threads;s_index++) br /nbsp;{ br /nbsp; if(pthread_create((pthread_t *)(amp;s_pthread[s_index]), (pthread_attr_t *)0, mz_test_thread, (void *)(amp;s_test_value)) != 0) br /nbsp; { br /nbsp; nbsp;(void)fputs(pthread_create error\n, stderr); br /nbsp; nbsp;break; br /nbsp; } br /nbsp;} br /nbsp;(void)fprintf(stdout, threads=%d\n, s_index); br /nbsp;while(g_mz_ctrl_break == 0) br /nbsp;{ br /#if def_use_lock != (0) br /nbsp; mz_lock((int *)(amp;g_mz_lock)); br /#endif br /nbsp; if(s_test_value == 0)(void)fprintf(stdout, \n\x1b[1;31munsafe value = %d\x1b[0m\n, s_test_value); br /nbsp; else br /nbsp; { br /nbsp; nbsp;(void)fprintf(stdout, \rsafe value = %d, s_test_value); br /nbsp; nbsp;(void)fflush(stdout); br /nbsp; } br /#if def_use_lock != (0) br /nbsp; mz_unlock((int *)(amp;g_mz_lock)); br /#endif br /nbsp; mz_load_balance(); br /nbsp;} br /nbsp;while((--s_index) gt;= 0)(void)pthread_join(s_pthread[s_index], (void **)0); br /nbsp;(void)fputs(\n\x1b[0mExit.\n, stdout); br /nbsp;return(0); br /} br /br //* vim: set expandtab: */ br //* End of source *//TD/TR/TBODY/TABLE
받은 트랙백이 없고,
댓글이 없습니다.
mutex.tar.gz
글
댓글을 달아 주세요
댓글 RSS 주소 : http://blog.minzkn.com/rss/comment/150댓글 ATOM 주소 : http://blog.minzkn.com/atom/comment/150