Linux Threads Programming
Linux Threads Programming
LinuxThreads´Â ´ÙÁß ¾²·¹µå ÇÁ·Î±×·¡¹ÖÀ» À§ÇÑ ¸®´ª½º ¶óÀ̺귯¸®ÀÌ´Ù.
LinuxThreads´Â Ä¿³Î ¼öÁØÀÇ ¾²·¹µå¸¦ Á¦°øÇÑ´Ù; ¾²·¹µåµéÀº clone()
½Ã½ºÅÛÄÝ¿¡ ÀÇÇØ ¸¸µé¾îÁö°í ¸ðµç ½ºÄÉÁÙ¸µÀº Ä¿³Î¿¡¼ ÀÌ·ç¾îÁø´Ù.
Posix 1003.1c API¸¦ ±¸ÇöÇÏ¿´°í Ä¿³Î 2.0.0ÀÌ»óÀÇ Ä¿³Î°ú ÀûÀýÇÑ
C ¶óÀ̺귯¸®¸¦ °¡Áö°í ÀÖ´Â ¾î¶°ÇÑ ¸®´ª½º ½Ã½ºÅÛ¿¡ µ¿ÀÛÇÑ´Ù.
¾²·¹µå´Â ÇÁ·Î±×·¥À» ÅëÇÑ Á¦¾îÀÇ ¼øÂ÷ÀûÀÎ È帧ÀÌ´Ù. ±×·¡¼ ´ÙÁß ¾²·¹µå
ÇÁ·Î±×·¡¹ÖÀº ¿©·¯ Á¦¾î ¾²·¹µå°¡ ÇÑ ÇÁ·Î±×·¥¿¡¼ µ¿½Ã¿¡ ¼öÇàÇÏ´Â º´·Ä
ÇÁ·Î±×·¡¹ÖÀÇ ÇÑ ÇüÅÂÀÌ´Ù.
´ÙÁß ¾²·¹µå ÇÁ·Î±×·¡¹ÖÀº ¸ðµç ¾²·¹µå°¡ °°Àº ¸Þ¸ð¸® °ø°£À» (±×¸®°í
ÆÄÀÏ µð½ºÅ©¸³ÅÍ¿Í °°Àº ÀϺΠ½Ã½ºÅÛ ÀÚ¿øµéÀ») °øÀ¯ÇÏ´Â À¯´Ð½º ½ºÅ¸ÀÏÀÇ
´ÙÁß ÇÁ·Î¼¼½Ì°ú´Â ´Ù¸£´Ù. ´ë½Å¿¡ À¯´Ð½ºÀÇ ÇÁ·Î¼¼½º¿Í °°ÀÌ ÀڽŸ¸ÀÇ
°íÀ¯ ¸Þ¸ð¸®»ó¿¡ µ¿ÀÛÇÑ´Ù. ±×·¡¼ ÇÑ ÇÁ·Î¼¼½ºÀÇ µÎ ¾²·¹µå »çÀÌÀÇ ¹®¸Æ
±³È¯(context switch)´Â µÎ ÇÁ·Î¼¼½º »çÀÌÀÇ ¹®¸Æ ±³È¯º¸´Ù ±²ÀåÇÑ ¼ö¿ù
ÇÏ´Ù.
¾²·¹µå¸¦ »ç¿ëÇÏ´Â µÎ °¡Áö ÁÖ¿äÇÑ ÀÌÀ¯°¡ ÀÖ´Ù:
- ¾î¶² ÇÁ·Î±×·¥µéÀº ÇϳªÀÇ Á¦¾î È帧 º¸´Ù´Â ¼·Î Åë½ÅÇÏ´Â ¿©·¯
¾²·¹µå·Î ÀÛ¼ºµÉ ¶§¸¸ ÃÖ°íÀÇ ¼º´ÉÀ» ³¾ ¼ö ÀÖ´Ù. (Áï, ¼¹öµé)
- ´ÙÁß ÇÁ·Î¼¼¼ ½Ã½ºÅÛ¿¡¼, ¾²·¹µåµéÀº ¿©·¯ ÇÁ·Î¼¼¼»ó¿¡¼ º´·ÄÀû
À¸·Î ¼öÇàµÉ ¼ö ÀÖ´Ù. ÀÌ´Â ÇÑ ÇÁ·Î±×·¥ÀÌ ´Ù¸¥ ÇÁ·Î¼¼¼¿¡ ÀÛ¾÷À»
ºÐ¹èÇÒ ¼ö ÀÖ°Ô ÇØÁØ´Ù. ÀÌ·± ÇÁ·Î±×·¥Àº ÇÑ ¹ø¿¡ ÇÑ CPU¸¸À» »ç¿ëÇÒ
¼ö ÀÖ´Â ´ÜÀÏ ¾²·¹µå ÇÁ·Î±×·¥ º¸´Ù ÈξÀ ´õ ºü¸£´Ù.
¾²·¹µå¿¡ ÀÇÇØ °øÀ¯µÇ´Â ¸Þ¸ð¸®¸¦ Á¢±ÙÇÏ´Â µ¥´Â ´õ ÁÖÀÇ°¡ ÇÊ¿äÇÏ´Ù.
º´·Ä ÇÁ·Î±×·¥Àº ÀϹÝÀûÀÎ Áö¿ª ¸Þ¸ð¸®Ã³·³ °øÀ¯ ¸Þ¸ð¸® °´Ã¼¸¦ Á¢±ÙÇÒ ¼ö
¾ø±â ¶§¹®ÀÌ´Ù.
¿øÀÚ¼º(atomicity)´Â ¾î¶² °´Ã¼¿¡ ´ëÇÑ ¿¬»êÀº ºÐ¸®µÉ ¼ö ¾ø´Â, ÀÎÅÍ·´Æ®
µÇ´Â ¾Ê´Â °úÁ¤À¸·Î ÀÌ·ç¾îÁ®¾ß µÇ´Ù´Â °³³äÀ» ¸»ÇÑ´Ù. °øÀ¯ ¸Þ¸ð¸®»óÀÇ
µ¥ÀÌÅÍ¿¡ ´ëÇÑ ¿¬»êÀº ¿øÀÚÀûÀ¸·Î ÀÌ·ç¾îÁú ¼ö ¾ø´Ù. °Ô´Ù°¡ GCC ÄÄÆÄÀÏ·¯
´Â Á¾Á¾ ·¹Áö½ºÅÍ¿¡ °øÀ¯ º¯¼öµéÀÇ °ªÀ» ¹öÆÛ¸µÇÏ´Â ÃÖÀûȸ¦ ¼öÇàÇÒ °Í
ÀÌ´Ù. ÀÌ·¸°Ô ¸Þ¸ð¸® ¿¬»êÀ» ÇÇÇÏ´Â °ÍÀÌ¶óµµ ¸ðµç ÇÁ·Î¼¼¼°¡ °øÀ¯
µ¥ÀÌÅÍÀÇ °ªÀÌ º¯°æµÈ °ÍÀº ¾Ë ¼ö ÀÖ¾î¾ß¸¸ ÇÑ´Ù.
·¹Áö½ºÅÍ¿¡ °øÀ¯ ¸Þ¸ð¸®ÀÇ °ªÀ» ¹öÆÛ¸µÇÏ´Â GCCÀÇ ÃÖÀûȸ¦ ¸·±â À§ÇØ
°øÀ¯ ¸Þ¸ð¸® »óÀÇ ¸ðµç °´Ã¼´Â volatile ¼Ó¼ºÀÇ Å¸ÀÔÀ¸·Î ¼±¾ðµÇ¾î¾ß
ÇÑ´Ù. ´Ü ÇÑ wordÀÇ volatile °´Ã¼¸¦ ÀÐ°í ¾µ´Â °ÍÀº ¿øÀÚÀûÀ¸·Î ÀÌ·ç¾î
Áö±â ¶§¹®ÀÌ´Ù.
°á°ú°ªÀ» Àоî¿À±â ÀúÀåÇÏ´Â °ÍÀº µ¶¸³µÈ ¸Þ¸ð¸® ¿¬»êÀÌ´Ù: ++iÀº Ç×»ó
°øÀ¯ ¸Þ¸ð¸® »óÀÇ iÀ» 1¸¸Å Áõ°¡½ÃÅ°Áö´Â ¾Ê´Â´Ù. µÎ ¿¬»ê »çÀÌ¿¡ ´Ù¸¥
ÇÁ·Î¼¼¼°¡ iÀ» Á¢±ÙÇÒ ¼ö Àֱ⠶§¹®ÀÌ´Ù. ±×·¡¼ µÎ ÇÁ·Î¼¼½º°¡ µÑ ´Ù
++iÀ» ¼öÇàÇÑ´Ù¸é 2°¡ ¾Æ´Ñ 1¸¸À» Áõ°¡µÉ ¼öµµ ÀÖ´Ù.
±×·¡¼ ÇÑ ¾²·¹µå°¡ º¯¼öÀÇ °ªÀ» ¹Ù²Ù´Â µ¿¾ÈÀº ´Ù¸¥ ¾²·¹µå°¡ ±× º¯¼ö¿¡
´ëÇÑ ÀÛ¾÷À» ÇÒ ¼ö ¾ø°Ô ÇÏ´Â ½Ã½ºÅÛ ÄÝÀÌ ÇÊ¿äÇÏ´Ù. ÀÌ´Â ¾Æ·¡ ¼³¸íÇÑ
lock ¹æ¹ýÀ¸·Î ±¸ÇöµÈ´Ù.
°øÀ¯ º¯¼öÀÇ °ªÀ» ¹Ù²Ù´Â ·çƾÀ» ¼öÇàÇÏ´Â µÎ ¾²·¹µå°¡ ÀÖ´Ù°í °¡Á¤À»
ÇÏÀÚ. ±× ·çƾÀÌ Á¤È®ÇÑ °á°ú¸¦ ¾ò±â À§Çؼ´Â ´ÙÀ½°ú °°ÀÌ ÇØ¾ß ÇÑ´Ù.
- i º¯¼ö¿¡ ´ëÇØ lockÀ» °Ç´Ù.
- Àá±ä º¯¼öÀÇ °ªÀ» ¼öÁ¤ÇÑ´Ù.
- lockÀ» Á¦°ÅÇÑ´Ù.
ÇÑ º¯¼ö¿¡ ´ëÇÑ lockÀÌ °É¸± ¶§ ±× lockÀ» °Ç ¾²·¹µå¸¸ÀÌ ±× °ªÀ» ¹Ù²Ü ¼ö
ÀÖ´Ù. Àá±Ù ¶§¹®¿¡ ´Ù¸¥ ¾²·¹µåµéÀº ºí·°ÀÌ µÉ °ÍÀÌ´Ù. ÇÑ º¯¼ö¿¡ ´ëÇؼ
´Â ÇÑ ¹ø¿¡ ÇϳªÀÇ lock¸¸ÀÌ Çã¿ëµÇ±â ¶§¹®ÀÌ´Ù. ¤½Ã¹¹ø° ¾²·¹µå°¡ lock
À» Á¦°ÅÇÒ ¶§¸¸ µÎ¹ø° ¾²·¹µå°¡ lockÀ» °É ¼ö ÀÖ´Ù.
±× °á°ú °øÀ¯ º¯¼ö¸¦ ÀÌ¿ëÇÏ´Â °ÍÀº ´Ù¸¥ ÇÁ·Î¼¼¼µéÀÇ È°µ¿À» ´À¸®°Ô ÇÒ
Áöµµ ¸ðµç´Ù. ÇÏÁö¸¸ ÀϹÝÀûÀÎ ÂüÁ¶´Â Áö¿ª ij½Ã¸¦ ÀÌ¿ëÇÑ´Ù.
LinuxThreads°¡ Á¦°øÇÏ´Â °ÍÀº ¾²·¹µå ·çƾµéÀÇ ÇÁ·ÎÅäŸÀÔÀ» ¼±¾ðÇÏ´Â
/usr/include/pthread.h Çì´õ¸¦ ÅëÇؼ ÀÌ¿ë °¡´ÉÇÏ´Ù.
´ÙÁß ¾²·¹µå ÇÁ·Î±×·¥ÀÇ ÀÛ¼ºÀº ±âº»ÀûÀ¸·Î µÎ ´Ü°èÀÇ °úÁ¤ÀÌ´Ù:
- °øÀ¯ º¯¼öµé¿¡ lockÀ» °É°í ¾²·¹µå¸¦ ¸¸µé±â À§ÇÑ pthread ·çƾµéÀ»
»ç¿ëÇÑ´Ù.
- ¾²·¹µå ¼ºê ·çƾ¿¡ ³Ñ°Ü¾ß ÇÒ ¸ð¸¥ ÀÎÀÚµéÀ» Æ÷ÇÔÇÏ´Â ±¸Á¶Ã¼¸¦
¸¸µç´Ù.
¸î °¡Áö ±âº»ÀûÀÎ pthread.hÀÇ ·çƾµéÀ» °£´ÜÈ÷ ¼³¸íÇÏ¸é¼ ÀÌ µÎ ´Ü°è¸¦
½ÇÆ캸ÀÚ.
Çؾ߸¸ Çϴ ù¹ø° Çൿµé ÁßÀÇ Çϳª´Â ¸ðµç lockµéÀ» ÃʱâÈÇÏ´Â
°ÍÀÌ´Ù. POSIX lockµéÀº pthread_mutex_t ŸÀÔÀÇ º¯¼ö·Î ¼±¾ðµÈ´Ù; °¢
lockÀ» ÃʱâÈÇϱâ À§Çã ´ÙÀ½ ·çƾÀ» È£ÃâÇÒ ÇÊ¿ä°¡ ÀÖ´Ù:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread
_mutexattr_t *mutexattr);
¹¾î¼ º¸¸é:
#include <pthread.h>
...
pthread_mutex_t lock;
pthread_mutex_init(&lock, NULL);
...
pthread_mutex_init ÇÔ¼ö´Â mutex ÀÎÀÚ°¡ °¡1¸£Å°´Â mutex °´Ã¼¸¦
mutexattr¿¡ ÀÇÇØ ¸í½ÃµÈ mutex ¼Ó¼º¿¡ µû¶ó Ãʱâȸ¦ ÇÑ´Ù. mutexattrÀÇ
NULLÀ̸é, µðÆúÆ® ¼Ó¼ºÀÌ »ç¿ëµÈ´Ù.
°è¼ÓÇì¼ ÀÌ ÃʱâÈµÈ lockµéÀ» ¾î¶»°Ô »ç¿ëÇÏ´ÂÁö º¸°Ú´Ù.
POSIX´Â °¢ ¾²·¹µå¸¦ ³ªÅ¸³»±â À§ÇØ »ç¿ëÀÚ°¡ pthread_t ŸÀÔÀÇ º¯¼ö¸¦
¼±¾ðÇϵµ·Ï ÇÑ´Ù. ´ÙÀ½ È£Ãâ·Î ¾²·¹µå°¡ »ý¼ºµÈ´Ù:
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void
*(*start_routine)(void *), void *arg);
¼º°øÇÑ´Ù¸é »õ·ÎÀÌ »ý¼ºµÈ ¾²·¹µåÀÇ id°¡ thread ÀÎÀÚ°¡ Áö½ÃÇÑ ¿µ¿ª¿¡
Á¤ÀåÀÌ µÇ°í 0ÀÎ ¸®ÅϵȴÙ. ¿¡·¯°¡ ¹ß»ýÇϸé 0ÀÌ ¾Æ´Ñ °ªÀÌ ¸®ÅϵȴÙ.
f() ·çƾÀ» ¼öÇàÇÏ´Â ¾²·¹µå¸¦ ¸¸µé°í f()¿¡ arg º¯¼ö¸¦ °¡¸£Å°´Â Æ÷ÀÌÅÍ
¸¦ ³Ñ±â±â À§Çؼ´Â ´ÙÀ½°ú °°ÀÌ ÇÑ´Ù:
#include <pthread.h>
...
pthread_t thread;
pthread_create(&thread, NULL, f, &arg).
...
f() ·çºóÀº ´ÙÀ½°ú °°Àº ÇÁ·ÎÅäŸÀÔÀ» °¡Á®¾ß ÇÑ´Ù:
void *f(void *arg);
¸¶Áö¸· ´Ü°è·Î f() ·çƾÀÇ °á°ú¸¦ Á¢±ÙÇϱâ Àü¿¡ ¸¸µç ¸ðµç ¾²·¹µå°¡ Á¾·á
ÇÒ ¶§±îÁö ±â´Ù·Á¾ß ÇÑ´Ù. ´ÙÀ½À» È£ÃâÇÑ´Ù:
int pthread_join(pthread_t th, void **thread_return);
th°¡ °¡¸£Å°´Â ¾²·¹µå°¡ Á¾·áÇÒ ¶§±îÁö À§ÀÇ ÇÔ¼ö¸¦ È£ÃâÇÑ ¾²·¹µåÀÇ ¼öÇà
À» ¸ØÃá´Ù.
¸¸¾à thread_returnÀÌ NULLÀ̴ϸé thÀÇ ¸®ÅÏ°ªÀº thread_returnÀÌ °¡¸®Å°
´Â ¿µ¿ª¿¡ ÀúÀåµÈ´Ù.
È£ÃâÇÑ ·çƾÀÇ Á¤º¸¸¦ ¾²·¹µå ·çƾ¿¡ ³Ñ±â´Â µÎ °¡Áö ¹æ¹ýÀÌ ÀÖ´Ù:
µÎ¹ø° °ÍÀÌ ÄÚµåÀÇ ¸ðµâ¼ºÀ» º¸ÀüÇÏ´Â µ¥ °¡Àå ÁÁÀº ¼±ÅÃÀÌ´Ù.
±¸Á¦Ã¼´Â ¼¼ °¡Áö ´Ü°èÀÇ Á¤º¸¸¦ Æ÷ÇÔÇØ¾ß ÇÑ´Ù; ù°·Î °øÀ¯ º¯¼öµé°ú
lockµé¿¡ °üÇÑ Á¤º¸, µÎ¹ø°·Î ·çƾ¿¡¼ ÇÊ¿ä·Î ÇÏ´Â ¸ðµç µ¥ÀÌÅÍ¿¡ ´ëÇÑ
Á¤º¸, ¼¼¹ø°·Î ¾²·¡µé¸¦ ±¸ºÐÇØÁÖ´Â id¿Í ¾²·¹µå°¡ ÀÌ¿ëÇÒ ¼ö ÀÖ´Â CPUÀÇ
¼ö¿¡ ´ëÇÑ Á¤º¸ (·±Å¸ÀÓ¿¡ ÀÌ Á¤º¸¸¦ Á¦°øÇÏ´Â °ÍÀÌ ´õ ½±´Ù).
±¸Á¶Ã¼ÀÇ Ã¹¹ø° ¿ä¼ÒÀ» »ìÆ캸ÀÚ; ³Ñ°ÜÁø Á¤º¸´Â ¸ðµç ¾²·¹µåµé »çÀÌÀÇ
°øÀ¯µµ´Í °ÍÀÌ ¾î¾ßÇÑ´Ù. ±×·¡¼ ÇÊ¿äÇÑ º¯¼öµé°ú lockµéÀÇ Æ÷ÀÎÅ͸¦ »ç¿ë
ÇØ¾ß ÇÑ´Ù. double ŸÀÔÀÇ °øÀ¯ º¯¼ö var¿Í ±× ¿¡ ´ëÇÑ lockÀ» ³Ñ±â±â
À§ÇØ ±¸Á¶Ã¼´Â µÎ ¸â¹ö º¯¼ö¸¦ °¡Á®¾ß¸¸ ÇÑ´Ù:
double volatile *var;
pthread_mutex_t *var_lock;
volatile ¼Ó¼ºÀÇ »ç¿ë À§Ä¡¿¡ ÁÖ¸ñÇ϶ó. ÀÌ´Â Æ÷ÀÎÅÍ ÀÚü°¡ ¾Æ´Ï¶ó var°¡
volatileÀÓÀ» ³ªÅ¸³½´Ù.
¾²·¡µé¸¦ ÀÌ¿ëÇÏ¿© ½±°Ô º´·Äȸ¦ ÇÒ ¼ö ÀÖ´Â ÇÁ·Î±×·¥ÀÇ ¿¹´Â µÎ º¤ÅÍÀÇ
½ºÄ®¶óÄÚ°öÀ» °è»êÀÌ´Ù.
ÁÖ¼®À» ºÙÀÎ Äڵ带 Á¦½ÃÇÑ´Ù.
/* ÄÄÆÄÀÏ ÇÏ·Á¸é gcc -D_REENTRANT -lpthread */
#include <stdio.h>
#include <pthread.h>
/* ¾Ë¸ÂÀº ±¸Á¶Ã¼ ¼±¾ð */
typedef struct {
double volatile *p_s; /* ½ºÄ®¶ó °öÀÇ °øÀ¯ º¯¼ö */
pthread_mutex_t *p_s_lock; /* º¯¼ö sÀÇ lock */
int n; /* ¾²·¹µåÀÇ ¼ö */
int nproc; /* ÀÌ¿ëÇÒ ¼ö ÀÖ´Â ÇÁ·Î¼¼¼ÀÇ ¼ö */
double *x; /* ù¹ø° º¤ÅÍÀÇ µ¥ÀÌÅÍ */
double *y; /* µÎ¹ø° º¤ÅÍÀÇ µ¥ÀÌÅÍ */
int l; /* º¤ÅÍÀÇ ±æÀÌ */
} DATA;
void *SMP_scalprod(void *arg)
{
register double localsum;
long i;
DATA D = *(DATA *)arg;
localsum = 0.0;
/* °¢ ¾²·¹µå´Â i = D.n¿¡¼ ºÎÅÍ ½ºÄ®¶ó °öÀ» ½ÃÀÛÇÑ´Ù.
D.n = 1, 2, ...
D.nproc °ªÀ» °®´Â´Ù. Á¤È®È÷ D.nproc°³ÀÇ ¾²·¹µå°¡ ÀÖ±â
¶§¹®¿¡ iÀÇ Áõ°¡ °°Àº D.nprocÀÌ´Ù. */
for(i = D.n; i < D.l; i += D.nproc)
localsum += D.x[i]*D.y[i];
/* s¿¡ ´ëÇÑ lockÀ» °Ç´Ù ... */
pthread_mutex_lock(D.p_s_lock);
/* ... sÀÇ °ªÀ» ¹Ù²Û´Ù. ... */
*(D.p_s) += localsum;
/* ... ±×¸®°í lock¸¦ Á¦°ÅÇÑ´Ù. */
pthread_mutex_unlock(D.p_s_lock);
return NULL;
}
#define L 9 /* º¤ÅÍÀÇ Â÷¿ø */
int main(int argc, char **argv)
{
pthread_t *thread;
void *retval;
int cpu, i;
DATA *A;
volatile double s = 0; /* °øÀ¯ º¯¼ö */
pthread_mutex_t s_lock;
double x[L], y[L];
if (argc != 2) {
printf("usage: %s <number of CPU>\n", argv[0]);
exit(1);
}
cpu = atoi(argv[1]);
thread = (pthread_t *) calloc(cpu, sizeof(pthread_t));
A = (DATA *) calloc(cpu, sizeof(DATA));
for (i = 0; i < L; i++)
x[i] = y[i] = i;
/* lock º¯¼ö¸¦ ÃʱâÈÇÑ´Ù. */
pthread_mutex_init(&s_lock, NULL);
for (i = 0; i < cpu; i++) {
/* ±¸Á¶Ã¼¸¦ ÃʱâÈÇÑ´Ù. */
A[i].n = i; /* ¾²·¹µåÀÇ ¼ö */
A[i].x = x;
A[i].y = y;
A[i].l = L;
A[i].nproc = cpu; /* CPUÀÇ ¼ö */
A[i].p_s = &s;
A[i].p_s_lock = &s_lock;
if (pthread_create(&thread[i], NULL, SMP_scalprod,
&A[i])) {
fprintf(stderr, "%s: cannot make thread\n",
argv[0]);
exit(1);
}
}
for (i = 0; i < cpu; i++) {
if (pthread_join(thread[i], &retval)) {
fprintf(stderr, "%s: cannot join thread\n",
argv[0]);
exit(1);
}
}
printf("s = %f\n", s);
exit(0);
}
Copyright ¨Ï 1999, Matteo Dell'Omodarme
Published in Issue 48 of Linux Gazette, December 1999
Linux Threads Programming
Linux Threads Programming
LinuxThreads´Â ´ÙÁß ¾²·¹µå ÇÁ·Î±×·¡¹ÖÀ» À§ÇÑ ¸®´ª½º ¶óÀ̺귯¸®ÀÌ´Ù.
LinuxThreads´Â Ä¿³Î ¼öÁØÀÇ ¾²·¹µå¸¦ Á¦°øÇÑ´Ù; ¾²·¹µåµéÀº clone()
½Ã½ºÅÛÄÝ¿¡ ÀÇÇØ ¸¸µé¾îÁö°í ¸ðµç ½ºÄÉÁÙ¸µÀº Ä¿³Î¿¡¼ ÀÌ·ç¾îÁø´Ù.
Posix 1003.1c API¸¦ ±¸ÇöÇÏ¿´°í Ä¿³Î 2.0.0ÀÌ»óÀÇ Ä¿³Î°ú ÀûÀýÇÑ
C ¶óÀ̺귯¸®¸¦ °¡Áö°í ÀÖ´Â ¾î¶°ÇÑ ¸®´ª½º ½Ã½ºÅÛ¿¡ µ¿ÀÛÇÑ´Ù.
¾²·¹µå´Â ÇÁ·Î±×·¥À» ÅëÇÑ Á¦¾îÀÇ ¼øÂ÷ÀûÀÎ È帧ÀÌ´Ù. ±×·¡¼ ´ÙÁß ¾²·¹µå
ÇÁ·Î±×·¡¹ÖÀº ¿©·¯ Á¦¾î ¾²·¹µå°¡ ÇÑ ÇÁ·Î±×·¥¿¡¼ µ¿½Ã¿¡ ¼öÇàÇÏ´Â º´·Ä
ÇÁ·Î±×·¡¹ÖÀÇ ÇÑ ÇüÅÂÀÌ´Ù.
´ÙÁß ¾²·¹µå ÇÁ·Î±×·¡¹ÖÀº ¸ðµç ¾²·¹µå°¡ °°Àº ¸Þ¸ð¸® °ø°£À» (±×¸®°í
ÆÄÀÏ µð½ºÅ©¸³ÅÍ¿Í °°Àº ÀϺΠ½Ã½ºÅÛ ÀÚ¿øµéÀ») °øÀ¯ÇÏ´Â À¯´Ð½º ½ºÅ¸ÀÏÀÇ
´ÙÁß ÇÁ·Î¼¼½Ì°ú´Â ´Ù¸£´Ù. ´ë½Å¿¡ À¯´Ð½ºÀÇ ÇÁ·Î¼¼½º¿Í °°ÀÌ ÀڽŸ¸ÀÇ
°íÀ¯ ¸Þ¸ð¸®»ó¿¡ µ¿ÀÛÇÑ´Ù. ±×·¡¼ ÇÑ ÇÁ·Î¼¼½ºÀÇ µÎ ¾²·¹µå »çÀÌÀÇ ¹®¸Æ
±³È¯(context switch)´Â µÎ ÇÁ·Î¼¼½º »çÀÌÀÇ ¹®¸Æ ±³È¯º¸´Ù ±²ÀåÇÑ ¼ö¿ù
ÇÏ´Ù.
¾²·¹µå¸¦ »ç¿ëÇÏ´Â µÎ °¡Áö ÁÖ¿äÇÑ ÀÌÀ¯°¡ ÀÖ´Ù:
- ¾î¶² ÇÁ·Î±×·¥µéÀº ÇϳªÀÇ Á¦¾î È帧 º¸´Ù´Â ¼·Î Åë½ÅÇÏ´Â ¿©·¯
¾²·¹µå·Î ÀÛ¼ºµÉ ¶§¸¸ ÃÖ°íÀÇ ¼º´ÉÀ» ³¾ ¼ö ÀÖ´Ù. (Áï, ¼¹öµé)
- ´ÙÁß ÇÁ·Î¼¼¼ ½Ã½ºÅÛ¿¡¼, ¾²·¹µåµéÀº ¿©·¯ ÇÁ·Î¼¼¼»ó¿¡¼ º´·ÄÀû
À¸·Î ¼öÇàµÉ ¼ö ÀÖ´Ù. ÀÌ´Â ÇÑ ÇÁ·Î±×·¥ÀÌ ´Ù¸¥ ÇÁ·Î¼¼¼¿¡ ÀÛ¾÷À»
ºÐ¹èÇÒ ¼ö ÀÖ°Ô ÇØÁØ´Ù. ÀÌ·± ÇÁ·Î±×·¥Àº ÇÑ ¹ø¿¡ ÇÑ CPU¸¸À» »ç¿ëÇÒ
¼ö ÀÖ´Â ´ÜÀÏ ¾²·¹µå ÇÁ·Î±×·¥ º¸´Ù ÈξÀ ´õ ºü¸£´Ù.
¾²·¹µå¿¡ ÀÇÇØ °øÀ¯µÇ´Â ¸Þ¸ð¸®¸¦ Á¢±ÙÇÏ´Â µ¥´Â ´õ ÁÖÀÇ°¡ ÇÊ¿äÇÏ´Ù.
º´·Ä ÇÁ·Î±×·¥Àº ÀϹÝÀûÀÎ Áö¿ª ¸Þ¸ð¸®Ã³·³ °øÀ¯ ¸Þ¸ð¸® °´Ã¼¸¦ Á¢±ÙÇÒ ¼ö
¾ø±â ¶§¹®ÀÌ´Ù.
¿øÀÚ¼º(atomicity)´Â ¾î¶² °´Ã¼¿¡ ´ëÇÑ ¿¬»êÀº ºÐ¸®µÉ ¼ö ¾ø´Â, ÀÎÅÍ·´Æ®
µÇ´Â ¾Ê´Â °úÁ¤À¸·Î ÀÌ·ç¾îÁ®¾ß µÇ´Ù´Â °³³äÀ» ¸»ÇÑ´Ù. °øÀ¯ ¸Þ¸ð¸®»óÀÇ
µ¥ÀÌÅÍ¿¡ ´ëÇÑ ¿¬»êÀº ¿øÀÚÀûÀ¸·Î ÀÌ·ç¾îÁú ¼ö ¾ø´Ù. °Ô´Ù°¡ GCC ÄÄÆÄÀÏ·¯
´Â Á¾Á¾ ·¹Áö½ºÅÍ¿¡ °øÀ¯ º¯¼öµéÀÇ °ªÀ» ¹öÆÛ¸µÇÏ´Â ÃÖÀûȸ¦ ¼öÇàÇÒ °Í
ÀÌ´Ù. ÀÌ·¸°Ô ¸Þ¸ð¸® ¿¬»êÀ» ÇÇÇÏ´Â °ÍÀÌ¶óµµ ¸ðµç ÇÁ·Î¼¼¼°¡ °øÀ¯
µ¥ÀÌÅÍÀÇ °ªÀÌ º¯°æµÈ °ÍÀº ¾Ë ¼ö ÀÖ¾î¾ß¸¸ ÇÑ´Ù.
·¹Áö½ºÅÍ¿¡ °øÀ¯ ¸Þ¸ð¸®ÀÇ °ªÀ» ¹öÆÛ¸µÇÏ´Â GCCÀÇ ÃÖÀûȸ¦ ¸·±â À§ÇØ
°øÀ¯ ¸Þ¸ð¸® »óÀÇ ¸ðµç °´Ã¼´Â volatile ¼Ó¼ºÀÇ Å¸ÀÔÀ¸·Î ¼±¾ðµÇ¾î¾ß
ÇÑ´Ù. ´Ü ÇÑ wordÀÇ volatile °´Ã¼¸¦ ÀÐ°í ¾µ´Â °ÍÀº ¿øÀÚÀûÀ¸·Î ÀÌ·ç¾î
Áö±â ¶§¹®ÀÌ´Ù.
°á°ú°ªÀ» Àоî¿À±â ÀúÀåÇÏ´Â °ÍÀº µ¶¸³µÈ ¸Þ¸ð¸® ¿¬»êÀÌ´Ù: ++iÀº Ç×»ó
°øÀ¯ ¸Þ¸ð¸® »óÀÇ iÀ» 1¸¸Å Áõ°¡½ÃÅ°Áö´Â ¾Ê´Â´Ù. µÎ ¿¬»ê »çÀÌ¿¡ ´Ù¸¥
ÇÁ·Î¼¼¼°¡ iÀ» Á¢±ÙÇÒ ¼ö Àֱ⠶§¹®ÀÌ´Ù. ±×·¡¼ µÎ ÇÁ·Î¼¼½º°¡ µÑ ´Ù
++iÀ» ¼öÇàÇÑ´Ù¸é 2°¡ ¾Æ´Ñ 1¸¸À» Áõ°¡µÉ ¼öµµ ÀÖ´Ù.
±×·¡¼ ÇÑ ¾²·¹µå°¡ º¯¼öÀÇ °ªÀ» ¹Ù²Ù´Â µ¿¾ÈÀº ´Ù¸¥ ¾²·¹µå°¡ ±× º¯¼ö¿¡
´ëÇÑ ÀÛ¾÷À» ÇÒ ¼ö ¾ø°Ô ÇÏ´Â ½Ã½ºÅÛ ÄÝÀÌ ÇÊ¿äÇÏ´Ù. ÀÌ´Â ¾Æ·¡ ¼³¸íÇÑ
lock ¹æ¹ýÀ¸·Î ±¸ÇöµÈ´Ù.
°øÀ¯ º¯¼öÀÇ °ªÀ» ¹Ù²Ù´Â ·çƾÀ» ¼öÇàÇÏ´Â µÎ ¾²·¹µå°¡ ÀÖ´Ù°í °¡Á¤À»
ÇÏÀÚ. ±× ·çƾÀÌ Á¤È®ÇÑ °á°ú¸¦ ¾ò±â À§Çؼ´Â ´ÙÀ½°ú °°ÀÌ ÇØ¾ß ÇÑ´Ù.
- i º¯¼ö¿¡ ´ëÇØ lockÀ» °Ç´Ù.
- Àá±ä º¯¼öÀÇ °ªÀ» ¼öÁ¤ÇÑ´Ù.
- lockÀ» Á¦°ÅÇÑ´Ù.
ÇÑ º¯¼ö¿¡ ´ëÇÑ lockÀÌ °É¸± ¶§ ±× lockÀ» °Ç ¾²·¹µå¸¸ÀÌ ±× °ªÀ» ¹Ù²Ü ¼ö
ÀÖ´Ù. Àá±Ù ¶§¹®¿¡ ´Ù¸¥ ¾²·¹µåµéÀº ºí·°ÀÌ µÉ °ÍÀÌ´Ù. ÇÑ º¯¼ö¿¡ ´ëÇؼ
´Â ÇÑ ¹ø¿¡ ÇϳªÀÇ lock¸¸ÀÌ Çã¿ëµÇ±â ¶§¹®ÀÌ´Ù. ¤½Ã¹¹ø° ¾²·¹µå°¡ lock
À» Á¦°ÅÇÒ ¶§¸¸ µÎ¹ø° ¾²·¹µå°¡ lockÀ» °É ¼ö ÀÖ´Ù.
±× °á°ú °øÀ¯ º¯¼ö¸¦ ÀÌ¿ëÇÏ´Â °ÍÀº ´Ù¸¥ ÇÁ·Î¼¼¼µéÀÇ È°µ¿À» ´À¸®°Ô ÇÒ
Áöµµ ¸ðµç´Ù. ÇÏÁö¸¸ ÀϹÝÀûÀÎ ÂüÁ¶´Â Áö¿ª ij½Ã¸¦ ÀÌ¿ëÇÑ´Ù.
LinuxThreads°¡ Á¦°øÇÏ´Â °ÍÀº ¾²·¹µå ·çƾµéÀÇ ÇÁ·ÎÅäŸÀÔÀ» ¼±¾ðÇÏ´Â
/usr/include/pthread.h Çì´õ¸¦ ÅëÇؼ ÀÌ¿ë °¡´ÉÇÏ´Ù.
´ÙÁß ¾²·¹µå ÇÁ·Î±×·¥ÀÇ ÀÛ¼ºÀº ±âº»ÀûÀ¸·Î µÎ ´Ü°èÀÇ °úÁ¤ÀÌ´Ù:
- °øÀ¯ º¯¼öµé¿¡ lockÀ» °É°í ¾²·¹µå¸¦ ¸¸µé±â À§ÇÑ pthread ·çƾµéÀ»
»ç¿ëÇÑ´Ù.
- ¾²·¹µå ¼ºê ·çƾ¿¡ ³Ñ°Ü¾ß ÇÒ ¸ð¸¥ ÀÎÀÚµéÀ» Æ÷ÇÔÇÏ´Â ±¸Á¶Ã¼¸¦
¸¸µç´Ù.
¸î °¡Áö ±âº»ÀûÀÎ pthread.hÀÇ ·çƾµéÀ» °£´ÜÈ÷ ¼³¸íÇÏ¸é¼ ÀÌ µÎ ´Ü°è¸¦
½ÇÆ캸ÀÚ.
Çؾ߸¸ Çϴ ù¹ø° Çൿµé ÁßÀÇ Çϳª´Â ¸ðµç lockµéÀ» ÃʱâÈÇÏ´Â
°ÍÀÌ´Ù. POSIX lockµéÀº pthread_mutex_t ŸÀÔÀÇ º¯¼ö·Î ¼±¾ðµÈ´Ù; °¢
lockÀ» ÃʱâÈÇϱâ À§Çã ´ÙÀ½ ·çƾÀ» È£ÃâÇÒ ÇÊ¿ä°¡ ÀÖ´Ù:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread
_mutexattr_t *mutexattr);
¹¾î¼ º¸¸é:
#include <pthread.h>
...
pthread_mutex_t lock;
pthread_mutex_init(&lock, NULL);
...
pthread_mutex_init ÇÔ¼ö´Â mutex ÀÎÀÚ°¡ °¡1¸£Å°´Â mutex °´Ã¼¸¦
mutexattr¿¡ ÀÇÇØ ¸í½ÃµÈ mutex ¼Ó¼º¿¡ µû¶ó Ãʱâȸ¦ ÇÑ´Ù. mutexattrÀÇ
NULLÀ̸é, µðÆúÆ® ¼Ó¼ºÀÌ »ç¿ëµÈ´Ù.
°è¼ÓÇì¼ ÀÌ ÃʱâÈµÈ lockµéÀ» ¾î¶»°Ô »ç¿ëÇÏ´ÂÁö º¸°Ú´Ù.
POSIX´Â °¢ ¾²·¹µå¸¦ ³ªÅ¸³»±â À§ÇØ »ç¿ëÀÚ°¡ pthread_t ŸÀÔÀÇ º¯¼ö¸¦
¼±¾ðÇϵµ·Ï ÇÑ´Ù. ´ÙÀ½ È£Ãâ·Î ¾²·¹µå°¡ »ý¼ºµÈ´Ù:
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void
*(*start_routine)(void *), void *arg);
¼º°øÇÑ´Ù¸é »õ·ÎÀÌ »ý¼ºµÈ ¾²·¹µåÀÇ id°¡ thread ÀÎÀÚ°¡ Áö½ÃÇÑ ¿µ¿ª¿¡
Á¤ÀåÀÌ µÇ°í 0ÀÎ ¸®ÅϵȴÙ. ¿¡·¯°¡ ¹ß»ýÇϸé 0ÀÌ ¾Æ´Ñ °ªÀÌ ¸®ÅϵȴÙ.
f() ·çƾÀ» ¼öÇàÇÏ´Â ¾²·¹µå¸¦ ¸¸µé°í f()¿¡ arg º¯¼ö¸¦ °¡¸£Å°´Â Æ÷ÀÌÅÍ
¸¦ ³Ñ±â±â À§Çؼ´Â ´ÙÀ½°ú °°ÀÌ ÇÑ´Ù:
#include <pthread.h>
...
pthread_t thread;
pthread_create(&thread, NULL, f, &arg).
...
f() ·çºóÀº ´ÙÀ½°ú °°Àº ÇÁ·ÎÅäŸÀÔÀ» °¡Á®¾ß ÇÑ´Ù:
void *f(void *arg);
¸¶Áö¸· ´Ü°è·Î f() ·çƾÀÇ °á°ú¸¦ Á¢±ÙÇϱâ Àü¿¡ ¸¸µç ¸ðµç ¾²·¹µå°¡ Á¾·á
ÇÒ ¶§±îÁö ±â´Ù·Á¾ß ÇÑ´Ù. ´ÙÀ½À» È£ÃâÇÑ´Ù:
int pthread_join(pthread_t th, void **thread_return);
th°¡ °¡¸£Å°´Â ¾²·¹µå°¡ Á¾·áÇÒ ¶§±îÁö À§ÀÇ ÇÔ¼ö¸¦ È£ÃâÇÑ ¾²·¹µåÀÇ ¼öÇà
À» ¸ØÃá´Ù.
¸¸¾à thread_returnÀÌ NULLÀ̴ϸé thÀÇ ¸®ÅÏ°ªÀº thread_returnÀÌ °¡¸®Å°
´Â ¿µ¿ª¿¡ ÀúÀåµÈ´Ù.
È£ÃâÇÑ ·çƾÀÇ Á¤º¸¸¦ ¾²·¹µå ·çƾ¿¡ ³Ñ±â´Â µÎ °¡Áö ¹æ¹ýÀÌ ÀÖ´Ù:
µÎ¹ø° °ÍÀÌ ÄÚµåÀÇ ¸ðµâ¼ºÀ» º¸ÀüÇÏ´Â µ¥ °¡Àå ÁÁÀº ¼±ÅÃÀÌ´Ù.
±¸Á¦Ã¼´Â ¼¼ °¡Áö ´Ü°èÀÇ Á¤º¸¸¦ Æ÷ÇÔÇØ¾ß ÇÑ´Ù; ù°·Î °øÀ¯ º¯¼öµé°ú
lockµé¿¡ °üÇÑ Á¤º¸, µÎ¹ø°·Î ·çƾ¿¡¼ ÇÊ¿ä·Î ÇÏ´Â ¸ðµç µ¥ÀÌÅÍ¿¡ ´ëÇÑ
Á¤º¸, ¼¼¹ø°·Î ¾²·¡µé¸¦ ±¸ºÐÇØÁÖ´Â id¿Í ¾²·¹µå°¡ ÀÌ¿ëÇÒ ¼ö ÀÖ´Â CPUÀÇ
¼ö¿¡ ´ëÇÑ Á¤º¸ (·±Å¸ÀÓ¿¡ ÀÌ Á¤º¸¸¦ Á¦°øÇÏ´Â °ÍÀÌ ´õ ½±´Ù).
±¸Á¶Ã¼ÀÇ Ã¹¹ø° ¿ä¼ÒÀ» »ìÆ캸ÀÚ; ³Ñ°ÜÁø Á¤º¸´Â ¸ðµç ¾²·¹µåµé »çÀÌÀÇ
°øÀ¯µµ´Í °ÍÀÌ ¾î¾ßÇÑ´Ù. ±×·¡¼ ÇÊ¿äÇÑ º¯¼öµé°ú lockµéÀÇ Æ÷ÀÎÅ͸¦ »ç¿ë
ÇØ¾ß ÇÑ´Ù. double ŸÀÔÀÇ °øÀ¯ º¯¼ö var¿Í ±× ¿¡ ´ëÇÑ lockÀ» ³Ñ±â±â
À§ÇØ ±¸Á¶Ã¼´Â µÎ ¸â¹ö º¯¼ö¸¦ °¡Á®¾ß¸¸ ÇÑ´Ù:
double volatile *var;
pthread_mutex_t *var_lock;
volatile ¼Ó¼ºÀÇ »ç¿ë À§Ä¡¿¡ ÁÖ¸ñÇ϶ó. ÀÌ´Â Æ÷ÀÎÅÍ ÀÚü°¡ ¾Æ´Ï¶ó var°¡
volatileÀÓÀ» ³ªÅ¸³½´Ù.
¾²·¡µé¸¦ ÀÌ¿ëÇÏ¿© ½±°Ô º´·Äȸ¦ ÇÒ ¼ö ÀÖ´Â ÇÁ·Î±×·¥ÀÇ ¿¹´Â µÎ º¤ÅÍÀÇ
½ºÄ®¶óÄÚ°öÀ» °è»êÀÌ´Ù.
ÁÖ¼®À» ºÙÀÎ Äڵ带 Á¦½ÃÇÑ´Ù.
/* ÄÄÆÄÀÏ ÇÏ·Á¸é gcc -D_REENTRANT -lpthread */
#include <stdio.h>
#include <pthread.h>
/* ¾Ë¸ÂÀº ±¸Á¶Ã¼ ¼±¾ð */
typedef struct {
double volatile *p_s; /* ½ºÄ®¶ó °öÀÇ °øÀ¯ º¯¼ö */
pthread_mutex_t *p_s_lock; /* º¯¼ö sÀÇ lock */
int n; /* ¾²·¹µåÀÇ ¼ö */
int nproc; /* ÀÌ¿ëÇÒ ¼ö ÀÖ´Â ÇÁ·Î¼¼¼ÀÇ ¼ö */
double *x; /* ù¹ø° º¤ÅÍÀÇ µ¥ÀÌÅÍ */
double *y; /* µÎ¹ø° º¤ÅÍÀÇ µ¥ÀÌÅÍ */
int l; /* º¤ÅÍÀÇ ±æÀÌ */
} DATA;
void *SMP_scalprod(void *arg)
{
register double localsum;
long i;
DATA D = *(DATA *)arg;
localsum = 0.0;
/* °¢ ¾²·¹µå´Â i = D.n¿¡¼ ºÎÅÍ ½ºÄ®¶ó °öÀ» ½ÃÀÛÇÑ´Ù.
D.n = 1, 2, ...
D.nproc °ªÀ» °®´Â´Ù. Á¤È®È÷ D.nproc°³ÀÇ ¾²·¹µå°¡ ÀÖ±â
¶§¹®¿¡ iÀÇ Áõ°¡ °°Àº D.nprocÀÌ´Ù. */
for(i = D.n; i < D.l; i += D.nproc)
localsum += D.x[i]*D.y[i];
/* s¿¡ ´ëÇÑ lockÀ» °Ç´Ù ... */
pthread_mutex_lock(D.p_s_lock);
/* ... sÀÇ °ªÀ» ¹Ù²Û´Ù. ... */
*(D.p_s) += localsum;
/* ... ±×¸®°í lock¸¦ Á¦°ÅÇÑ´Ù. */
pthread_mutex_unlock(D.p_s_lock);
return NULL;
}
#define L 9 /* º¤ÅÍÀÇ Â÷¿ø */
int main(int argc, char **argv)
{
pthread_t *thread;
void *retval;
int cpu, i;
DATA *A;
volatile double s = 0; /* °øÀ¯ º¯¼ö */
pthread_mutex_t s_lock;
double x[L], y[L];
if (argc != 2) {
printf("usage: %s <number of CPU>\n", argv[0]);
exit(1);
}
cpu = atoi(argv[1]);
thread = (pthread_t *) calloc(cpu, sizeof(pthread_t));
A = (DATA *) calloc(cpu, sizeof(DATA));
for (i = 0; i < L; i++)
x[i] = y[i] = i;
/* lock º¯¼ö¸¦ ÃʱâÈÇÑ´Ù. */
pthread_mutex_init(&s_lock, NULL);
for (i = 0; i < cpu; i++) {
/* ±¸Á¶Ã¼¸¦ ÃʱâÈÇÑ´Ù. */
A[i].n = i; /* ¾²·¹µåÀÇ ¼ö */
A[i].x = x;
A[i].y = y;
A[i].l = L;
A[i].nproc = cpu; /* CPUÀÇ ¼ö */
A[i].p_s = &s;
A[i].p_s_lock = &s_lock;
if (pthread_create(&thread[i], NULL, SMP_scalprod,
&A[i])) {
fprintf(stderr, "%s: cannot make thread\n",
argv[0]);
exit(1);
}
}
for (i = 0; i < cpu; i++) {
if (pthread_join(thread[i], &retval)) {
fprintf(stderr, "%s: cannot join thread\n",
argv[0]);
exit(1);
}
}
printf("s = %f\n", s);
exit(0);
}
Copyright ¨Ï 1999, Matteo Dell'Omodarme
Published in Issue 48 of Linux Gazette, December 1999