Multithread ÇÁ·Î±×·¥¿¡¼ °¡Àå Å« ¹®Á¦°¡ µ¿½Ã¿¡ ½ÇÇàÇÏ´Â ¿©·¯°³ÀÇ thread°£ÀÇ µ¿±âÈÀÔ´Ï´Ù. UPÀÇ °æ¿ì ±âº»ÀûÀ¸·Î ¾î´À ½ÃÁ¡¿¡ controlÀ» ´Ù¸¥ thread·Î ³Ñ±æ Áö¸¦ ¾Ë ¼ö ÀÖÀ¸¹Ç·Î ÇÁ·Î¼¼¼ÀÇ º°´Ù¸¥ Áö¿ø¾øÀ̵µ µ¿±âȰ¡ °¡´ÉÇÏÁö¸¸ MP¿¡¼± µ¿½Ã¿¡ ÀÛµ¿ÇÏ´Â ¿©·¯°³ÀÇ ÇÁ·Î¼¼¼µéÀ» µ¿±âȽÃŰ·Á¸é Ư¼öÇÑ ±â´ÉÀ» Á¦°øÇؾßÇÕ´Ï´Ù. ±âº»ÀûÀ¸·Ð ¸Þ¸ð¸®ÀÇ ¾î¶² °ªÀ» ÀÐ¾î¼ Á¶°ÇÀ» È®ÀÎÇÏ°í ±× °ª¿¡ ¾î¶² º¯È¸¦ ÁÖ´Â ÀÛ¾÷À» atomicÇÏ°Ô ¼öÇàÇÒ ¼ö ÀÖ¾î¾ßÇÕ´Ï´Ù. º¸Åë test and set bitÀ̳ª exchangeµîÀ» atomicÇÏ°Ô ¼öÇàÇÏ´Â ±â´ÉÀ» Á¦°øÇÏ°Ô µÇ´Âµ¥ ix86¿¡¼± µÎ°¡Áö ¸ðµÎ Áö¿øµË´Ï´Ù. (ix86¿¡¼± instruction¿¡ LOCK prefix¸¦ ºÙÀÌ¸é ´ëºÎºÐÀÇ instructionµéÀ» atomicÇÏ°Ô ¼öÇàÇÒ ¼ö ÀÖ½À´Ï´Ù.)
ÀÌ Àý¿¡¼± atomic test and set bitÀ» ÀÌ¿ëÇØ µ¿±âÈÀÇ ±âº»ÀûÀÎ ±¸¼º¿ä¼ÒÀÎ spin lockÀ» ¸¸µé¾îº¸°Ú½À´Ï´Ù. Pthread¸¦ »ç¿ëÇØ ¸î°³ÀÇ threadµé »çÀÌ¿¡¼ spinÀ» ÀÌ¿ëÇÑ µ¿±âȸ¦ ÇØº¼ÅÙµ¥, °¢°¢ÀÇ threadµéÀÌ µ¶¸³µÈ processor¿¡¼ ÀÛµ¿ÇÏ´Â °ÍÀÌ ¾Æ´Ï¶ó time sliceµÇ¾î ÀÛµ¿Çϱ⠶§¹®¿¡ spinÀ» »ç¿ëÇÏ´Â °ÍÀº ÁÁÀº »ý°¢Àº ¾Æ´Õ´Ï´Ù. ¿¹¸¦ µé±âÀ§ÇÑ °ÍÀ̶ó°í »ý°¢ÇϽñ⠹ٶø´Ï´Ù.
#include <stdio.h> #include <pthread.h> #include <time.h> static __inline__ int test_and_set_bit(int nr, volatile void *addr) { int oldbit; __asm__ __volatile__( "lock \n\t" "btsl %2, %1 \n\t" "sbbl %0, %0 " : "=r" (oldbit), "=m" (*(unsigned *)addr) : "Ir" (nr)); return oldbit; } typedef unsigned spin_t; static __inline__ void spin_lock(spin_t *spin) { if (test_and_set_bit(0, spin)) while (*(__volatile__ spin_t *)spin) ; } static __inline__ void spin_unlock(spin_t *spin) { *(__volatile__ spin_t *)spin = 0; } spin_t spin = 0; static __inline__ void waste_time(void) { time_t ltime; ltime = time(NULL); while (time(NULL) == ltime) ; } #define pp(fmt, arg...) printf("thread %d : "fmt, thread_no , ##arg) static void * thread_func(void *_arg) { int thread_no = (int)_arg; while (1) { pp("wasting time\n"); waste_time(); pp("entering critical section\n"); pp("now in critical section, wasting time\n"); waste_time(); pp("leaving critical section\n"); } return NULL; } static void * thread_sfunc(void *_arg) { int thread_no = (int)_arg; time_t ltime; while (1) { pp("wasting time\n"); waste_time(); pp("entering critical section\n"); spin_lock(&spin); pp("now in critical section, wasting time\n"); waste_time(); pp("leaving critical section\n"); spin_unlock(&spin); } return NULL; } int main(void) { pthread_t thread0, thread1, thread2, thread3; pthread_create(&thread0, NULL, thread_func, (void *)0); pthread_create(&thread1, NULL, thread_func, (void *)1); pthread_create(&thread2, NULL, thread_sfunc, (void *)2); pthread_create(&thread3, NULL, thread_sfunc, (void *)3); pthread_join(thread0, NULL); pthread_join(thread1, NULL); pthread_join(thread2, NULL); pthread_join(thread3, NULL); return 0; } |
4°³ÀÇ thread°¡ ½Ã°£º¸³»±â, critical sectionµé¾î°¡±â, ½Ã°£º¸³»±â, critical section³ª¿À±âÀÇ °úÁ¤À» ¹Ýº¹ÇÕ´Ï´Ù. 0¹ø°ú 1¹ø thread´Â ¾Æ¹«·± µ¿±âȵµ ÇÏÁö ¾Ê°í 2, 3Àº spinÀ» ÀÌ¿ëÇØ critical sectionÀ» º¸È£ÇÕ´Ï´Ù.
¿ì¼± test_and_set_bit ÇÔ¼ö¸¦ »ìÆìº¸µµ·Ï ÇϰڽÀ´Ï´Ù.
lock; btsl %2, %1 |
AtomicÇÏ°Ô *addrÀÇ nr¹øÂ° bitÀ» test and setÇÕ´Ï´Ù. TestÀÇ °á°ú´Â carry flag¿¡ ±â·ÏÀ̵˴ϴÙ.
sbbl %0, %0 |
À§ÀÇ btsl¿¡¼ CF±â·ÏµÈ test°á°ú¸¦ %0¿¡ ÀúÀåÇÕ´Ï´Ù. sbblÀº subtraction with carry·Î À§Ã³·³ °°Àº µÎ ¼ö·Î ½ÇÇàÇϸé carry flag°ú °°Àº ³í¸®°ªÀÌ operand¿¡ ÀúÀåµË´Ï´Ù.
Output, input ÁöÁ¤¿¡¼± nrÀÇ constrait°¡ "Ir"ÀÎ Á¡À» Á¦¿ÜÇÏ¸é º°´Ù¸¥ Á¡Àº ¾ø½À´Ï´Ù. nrÀÌ ÇÑ word¾È¿¡¼ÀÇ bit offsetÀ̹ǷΠimmediateÀÏ ¶§ 0~31»çÀÌ·Î Á¦ÇÑÀ» µÐ °ÍÀ̰í, ·¹Áö½ºÅÍ operandÀÏ ¶§´Â ÄÄÆÄÀÏŸÀÓ¿¡ È®ÀÎÇÒ ¼ö ¾ø±â ¶§¹®¿¡ ±×³É 'r'À» constraint·Î ÁØ °ÍÀÔ´Ï´Ù.
test_and_set_bitÀÌ ÀÖÀ¸¸é spinÀÇ ±¸ÇöÀº °£´ÜÇѵ¥¿ä. test_and_set_bitÀÇ °á°ú°ªÀÌ 0ÀÏ ¶§±îÁö ¹Ýº¹ÀûÀ¸·Î ¼öÇàÇÏ¸é µË´Ï´Ù. À§ÀÇ ÇÁ·Î±×·¥¿¡¼ ±â´Ù¸®´Â ºÎºÐÀ» while·Î ó¸®ÇÑ °ÍÀº lock; btslº¸´Ù º¸ÅëÀÇ memory read°¡ bus¿¡ ºÎ´ãÀ» ´ú Áֱ⠶§¹®ÀÔ´Ï´Ù. whileÀÇ Á¶°Ç¿¡¼ __volatile__·Î ij½ºÆÃÈÄ »ç¿ëÇÏ´Â °Ç gcc°¡ ·¹Áö½ºÅÍ¿¡ spinÀÇ °ªÀ» ÀÐÀº ÈÄ ±× °ªÀ» °è¼Ó testÇÏ´Â °ÍÀ» ¸·±â À§Çؼ ÀÔ´Ï´Ù. Gcc¿¡°Ô ÀÌ °ªÀº ÇöÀç ÇÁ·Î±×·¥ÀÇ ÁøÇà°ú °ü°è¾øÀÌ ¹Ù²ð ¼ö ÀÖ´Ù´Â °ÍÀ» ¾Ë·ÁÁÖ´Â °ÍÀÔ´Ï´Ù.
UnlockÀº ±×³É spinÀÇ °ªÀ» 0À¸·Î ÇÏ¸é µË´Ï´Ù. ¿ª½Ã memory¿¡ Á÷Á¢¾²µµ·Ï ÇϱâÀ§ÇØ __volatile__·Î ij½ºÆÃÈÄ »ç¿ëÇÏ´Â °ÍÀ» º¼ ¼ö ÀÖ½À´Ï´Ù. ±×³É spinÀ» __volatile__·Î ÁöÁ¤ÇØÁ־ µË´Ï´Ù.
Inline assembly´Â ´Ü¼øÇϹǷΠÄÄÆÄÀÏµÈ assembly´Â »ý·«ÇÏ°í ½ÇÇà °á°ú¸¦ º¸°Ú½À´Ï´Ù.
thread 0 : wasting time thread 1 : wasting time thread 2 : wasting time thread 3 : wasting time thread 0 : entering critical section thread 0 : now in critical section, wasting time thread 3 : entering critical section thread 3 : now in critical section, wasting time thread 2 : entering critical section thread 1 : entering critical section thread 1 : now in critical section, wasting time thread 1 : leaving critical section thread 1 : wasting time thread 0 : leaving critical section thread 0 : wasting time thread 3 : leaving critical section thread 3 : wasting time thread 2 : now in critical section, wasting time thread 2 : leaving critical section thread 2 : wasting time thread 1 : entering critical section thread 1 : now in critical section, wasting time thread 0 : entering critical section thread 0 : now in critical section, wasting time thread 3 : entering critical section thread 3 : now in critical section, wasting time thread 2 : entering critical section thread 1 : leaving critical section thread 1 : wasting time thread 0 : leaving critical section thread 0 : wasting time thread 3 : leaving critical section thread 3 : wasting time thread 2 : now in critical section, wasting time |
0°ú 1ÀÇ critical sectionÀº °ãÄ¡Áö¸¸ 2¿Í 3Àº °ãÄ¡Áö ¾ÊÀ½À» ¾Ë ¼ö ÀÖ½À´Ï´Ù.