RealTime SignalÀ» ÀÌ¿ëÇÑ Thread PoolÀÇ ±¸Çö
ÃÑ ÆäÀÌÁö ¼ö : 3224

Àüü ÇÔ¼ö/¿ë¾î»çÀü
Facebook Joinc ±×·ì   Joinc QA »çÀÌÆ®



joinc´Â Firefox¿Í chrome¿¡¼­ Å×½ºÆ® Çß½À´Ï´Ù. IE¿¡¼­´Â Å×À̺íÀÌ ±úÁö°Å³ª À̹ÌÁö°¡ º¸ÀÌÁö ¾ÊÀ» ¼ö ÀÖ½À´Ï´Ù. ƯÈ÷ ±¸±Û DocsÀ̹ÌÁöÀÇ °æ¿ì ¿¢¹Úó¸®µÉ ¼ö ÀÖ½À´Ï´Ù.


Docbook ¿ø¹®

RTS¿Í Thread PoolÀÇ °áÇÕ

RTS¿Í Thread PoolÀÇ °áÇÕ

À± »ó¹è

dreamyun@yahoo.co.kr

교정 과정
교정 0.82003³â 9¿ù 16ÀÏ 23½Ã
ÃÖÃÊ ¹®¼­ÀÛ¼º


1절. ¼Ò°³

RTS´Â ±âº»ÀûÀ¸·Î °í¼º´É ³×Æ®¿öÅ© ¾ÖÇø®ÄÉÀ̼ÇÀ» ÀÛ¼ºÇϱâ À§ÇÑ ¸ñÀûÀ¸·Î »ç¿ëµÈ´Ù. ÀÌ·± ÀÌÀ¯·Î ³×Æ®¿öÅ© ¾ÖÇø®ÄÉÀ̼ÇÀÇ Ã³¸®´É·ÂÀ» Çâ»ó½Ã۱â À§Çؼ­ »ç¿ëµÇ´Â Thread/Process pool µî°ú ÇÔ²² »ç¿ëµÇ´Â °æ¿ì°¡ ¸¹´Ù.

À̹ø °­Á¿¡¼­´Â Thread Pool°ú RTS¸¦ Á¶ÇÕÇØ¼­ °í¼º´É ³×Æ®¿öÅ© ¾ÖÇø®ÄÉÀ̼ÇÀ» ÀÛ¼ºÇÏ´Â ¹æ¹ý¿¡ ´ëÇØ¼­ ¾Ë¾Æº¸µµ·Ï ÇϰڴÙ.

ÀÌ ¹®¼­¸¦ ÀбâÀü¿¡ ¹Ýµå½Ã ÀÌÀüÀÇ RTS¹®¼­µéÀ» ÀÐ¾î º¸±â¹Ù¶õ´Ù. ±×·¸Áö ¾Ê´Ù¸é ÀÌÇØÇϱâ Èûµç ³»¿ëÀÌ ¸¹À» °ÍÀÌ´Ù.


2절. Á»´õ È¿À²ÀûÀÎ ³×Æ®¿öÅ© ¾ÖÇø®ÄÉÀ̼ÇÀ» À§Çؼ­

2.1절. RTS¿Í ¾²·¹µåÀÇ Á¶ÇÕ

RTS¿Í ¾²·¹µåÇ®ÀÇ Á¶ÇÕ¿¡ ´ëÇØ¼­ ¾Ë¾Æº¸±â Àü¿¡ ±× Àü´Ü°è °úÁ¤À̶ó°í º¼¼ö ÀÖ´Â RTS¿Í ¾²·¹µå¿ÍÀÇ Á¶ÇÕ¿¡ ´ëÇØ¼­ ¾Ë¾Æº¸ÀÚ.


ÀϹÝÀûÀÎ ¾²·¹µå¹× ÇÁ·Î¼¼½º ±â¹ÝÀÇ ³×Æ®¿öÅ© ¼­¹ö ¾ÖÇø®ÄÉÀ̼ǰú µ¿ÀÏÇÑ ¹æ¹ýÀ¸·Î Á¦À۵ȴÙ. Áï ¸ÞÀÎ ¾²·¹µå¿¡¼­ socket->bind->listen ÀÇ ¼ø¼­¸¦ µû¶ó¼­ µè±â ¼ÒÄÏÀ» ÀÛ¼ºÇϰí accept·Î Ŭ¶óÀ̾ðÆ®ÀÇ ¿¬°áÀ» ´ë±âÇϰí ÀÖ´Ù°¡ Ŭ¶óÀ̾ðÆ®ÀÇ ¿¬°áÀÌ ¸¸µé¾îÁö¸é Ŭ¶óÀÌ¾ðÆ®¿Í µ¥ÀÌÅÍ Åë½ÅÀ» À§ÇÑ ¾²·¹µå¸¦ »ý¼ºÇÏ´Â ¹æ¹ýÀÌ´Ù.

ÀÌµé °íÀüÀûÀÎ ¾²·¹µå/Æ÷Å©¹æ½Ä°úÀÇ Â÷ÀÌÁ¡À̶ó¸é µ¥ÀÌÅÍ Åë½ÅÀ» À§Çؼ­ RTS¸¦ »ç¿ëÇÑ´Ù´Â Á¡ÀÌ´Ù. RTS¸¦ Á¦´ë·Î Àû¿ëÇϱâ À§Çؼ­´Â À¯´Ð½ºÀÇ ¾²·¹µå¿¡¼­ ÀÛµ¿µÇ´Â ½Ã±×³Î ¸ÅÄ¿´ÏÁò¿¡ ´ëÇØ¼­ ÀÌÇØ¸¦ Çϰí ÀÖ¾î¾ß ÇÑ´Ù.

¸î¹ø ÀÌ »çÀÌÆ®ÀÇ ¹®¼­¸¦ ÅëÇØ¼­ °£Á¢ÀûÀ¸·Î ¾ð±ÞµÇ¾úÀ» °Çµ¥, ¾²·¹µå´Â ±âº»ÀûÀ¸·Î ½ºÅÃ, ¾²·¹µå, ÆÄÀÏ, ½Ã±×³Î µîÀÇ ÀÚ¿øÀ» ¼­·Î °øÀ¯ÇÏ°Ô µÈ´Ù. À̰ÍÀº À¯´Ð½º Ç¥ÁØ ½Ã±×³ÎÀÇ È®ÀåÆÇÀÎ RTS¿¡µµ µ¿ÀÏÇÏ°Ô Àû¿ëµÇ¸ç, ¸ðµç ¾²·¹µå¿¡¼­ °øÀ¯ÇÒ ¼ö ÀÖ´Ù. ÇÙ½ÉÀº ÇÁ·Î¼¼½º¿¡¼­ ½Ã±×³ÎÀ» ¹ÞÀ»°æ¿ì ƯÁ¤ ¾²·¹µå·Î ½Ã±×³ÎÀ» Àü´ÞµÇµµ·Ï ÇØ¾ßÇÑ´Ù´Â °ÍÀÌ´Ù.

´ÙÇàÈ÷(ȤÀº ´ç¿¬È÷) pthread¶óÀ̺귯¸®¿¡¼­´Â ´ÙÀ½°ú °°Àº ½Ã±×³Î°ú °ü·ÃµÈ ¶óÀ̺귯¸®¸¦ Á¦°øÇÑ´Ù.

#include <pthread.h>
#include <signal.h>

int pthread_sigmask(int how, const sigset_t *newmask, sigset_t *oldmask);
			
pthread_sigmask(3)¸¦ ÀÌ¿ëÇÏ¸é °¢°¢ÀÇ ¾²·¹µå°¡ ¾î¶² ½Ã±×³Î¼Â(newmask)¿¡ ´ëÇØ¼­ ƯÁ¤ÇÑ Çൿ(how)¸¦ ÇÒ ¼ö ÀÖµµ·Ï ¸¸µé ¼ö ÀÖ´Ù.

¶Ç ÇѰ¡Áö ½Å°æ½á¾ßÇÒ Á¡Àº °¢°¢ÀÇ ¾²·¹µå°¡ ¹Þ¾Æµé¿©¾ßÇÒ RTS°¡ ´Þ¶ó¾ß ÇÑ´Ù´Â Á¡ÀÌ´Ù. ¸ðµç »ý¼ºµÈ ¾²·¹µå°¡ µ¿ÀÏÇÑ SIGRTMIN¸¸À» »ç¿ëÇÏ°Ô µÈ´Ù¸é SIGRTMINÀÌ ¹ß»ýÇßÀ» ¶§ ¾î´À ¾²·¹µå·Î RTS°¡ Àü´ÞµÇ¾î¾ß ÇÒÁö ¾Ë ¼ö ¾øÀ» °ÍÀÌ´Ù.

À§ÀÇ ¹®Á¦´Â °¢ »ý¼ºµÇ´Â ¾²·¹µå¸¶´Ù ´Ù¸¥ RTS°¡ Àü´ÞµÇ°Ô ÇϹǷνá ÇØ°áÇÒ ¼ö ÀÖ´Ù. ¸®´ª½ºÀÇ °æ¿ì SIGRTMIN¿¡¼­ ºÎÅÍ SIGRTMAX±îÁö 32°³ÀÇ RTS°¡ Á¸ÀçÇϹǷΠ°¢ ¾²·¹µå¸¶´Ù ´Ù¸¥ RTS¸¦ ó¸®Çϵµ·Ï ¸¸µé¾î ÁÙ ¼ö ÀÖ´Ù. Ŭ¶óÀÌ¾ðÆ®°¡ ¿¬°áÇØ¼­ A¾²·¹µå°¡ »ý¼ºµÇ¾ú´Ù¸é, Ŭ¶óÀÌ¾ðÆ®¿ÍÀÇ ¿¬°á¼ÒÄÏ¿¡ À̺¥Æ®°¡ ¹ß»ýÇßÀ» ¶§ SIGRTMIN+1ÀÌ Àü´ÞµÇµµ·Ï Çϰí, ¶Ç´Ù¸¥ Ŭ¶óÀÌ¾ðÆ®°¡ ¿¬°áµÇ¾î¼­ B¾²·¹µå°¡ »ý¼ºµÇ¾ú´Ù¸é ÀÌ ¿¬°á¼ÒÄÏ¿¡ ´ëÇØ¼­ SIGRTMIN+2°¡ ¹ß»ýÇϵµ·Ï ÇÏ´Â ½ÄÀÌ´Ù.

¿©±â¿¡¼­´Â ¹æ¹ý·ÐÀûÀÎ ¾ê±â¸¸ ÇÏ°í ½ÇÁ¦ Äڵ带 ÀÛ¼ºÇÏÁö´Â ¾ÊÀ» °ÍÀÌ´Ù. ¾îÂ÷ÇÇ ´ÙÀ½Àå¿¡¼­ ¸ðµÎ ´Ù·ç¾îÁú ³»¿ëÀ̱⠶§¹®ÀÌ´Ù.


2.2절. RTS¿Í Thread PoolÀÇ Á¶ÇÕ

±×·³ ÀÌÁ¦ºÎÅÍ ÁøÁ¤À¸·Î °ü½ÉÀÖ¾îÇÏ´Â RTS¿Í ¾²·¹µå Ç®°úÀÇ Á¶ÇÕ¿¡ ´ëÇØ¼­ ¾Ë¾Æº¸µµ·Ï ÇϰڴÙ. ¿©±â¿¡ ÀÖ´Â ³»¿ëÀ» ÃæºÐÈ÷ ÀÌÇØÇÑ´Ù¸é ´ýÀ¸·Î 2.1절±îÁö ÀÌÇØÇÒ ¼ö ÀÖ°Ô µÉ °ÍÀÌ´Ù.

¿©±â¿¡¼­´Â RTS¿Í ¾²·¹µåÇ®À» Á¶ÇÕÇÔÀ¸·Î½á ¾òÀ» ¼ö ÀÖ´Â ÀåÁ¡°ú ¾î¶² ¹æ½ÄÀ¸·Î Á¶ÇÕÀÌ °¡´ÉÇÑÁö¿¡ ´ëÇØ¼­ ¼³¸íÇϵµ·Ï ÇϰڴÙ.


2.2.1절. ¾òÀ» ¼ö ÀÖ´Â ÀåÁ¡

¾²·¹µå Ç®¿¡ ´ëÇØ¼­´Â ¾²·¹µå Ç® ÀÛ¼º¿¡¼­ °£´ÜÇÏ°Ô ¾ð±ÞÇß¾ú´Ù. ±×·¸´Ù¸é RTS¿Í ¾²·¹µå Ç®À» Á¶ÇÕÇØ¼­ »ç¿ëÇÒ °æ¿ì ¾òÀ» ¼ö ÀÖ´Â ÀåÁ¡¿¡ ´ëÇØ¼­ ¿ì¼±¾Ë¾Æº¸µµ·Ï ÇÏÀÚ.

  1. ¹Ì¸® »ý¼ºµÈ ¾²·¹µå¿¡¼­ Ŭ¶óÀÌ¾ðÆ®¸¦ ó¸®ÇÏ°Ô µÇ¹Ç·Î ¾²·¹µå »ý¼º¿¡ ´ëÇÑ ºñ¿ëÀ» ÁÙÀÏ ¼ö ÀÖ´Ù. ÀÌ·¯ÇÑ ±â¼úÀº À¥¼­¹ö¿Í °°ÀÌ ¿¬°á°ú Á¾·á°¡ ºó¹øÇÑ ¼­¹ö ¾ÖÇø®ÄÉÀ̼ǿ¡ ƯÈ÷ À¯¿ëÇÒ °ÍÀÌ´Ù. ½ÇÁ¦ ¸¹Àº À¥¼­¹öµéÀº ¾²·¹µåÇ®(ȤÀº ÇÁ·Î¼¼½º Ç®)À» ÀÌ¿ëÇØ¼­ ±¸ÇöµÈ´Ù.

    ÀÌ ¿Ü¿¡µµ ºó¹øÇÑ µ¥ÀÌÅÍ ±³È¯ÀÌ ¹ß»ýÇÏ´Â °ÔÀÓ¼­¹ö¿Í °°Àº °÷¿¡µµ ÈǸ¢ÇÏ°Ô ÀÀ¿ë µÉ¼ö ÀÖÀ» °ÍÀÌ´Ù.

  2. ƯÁ¤ ¼ÒÄÏ¿¡ À̺¥Æ®°¡ ¹ß»ýÇßÀ» ¶§ º°´Ù¸¥ ¿¬»ê¾øÀÌ ÇØ´ç ¼ÒÄÏÀ» ó¸®ÇÏ´Â ¾²·¹µå¿¡¼­ À̺¥Æ®¸¦ (ÀÚµ¿ÀûÀ¸·Î) °¨ÁöÇϰí ó¸® ÇÒ ¼ö ÀÖµµ·Ï µµ¿ÍÁØ´Ù.

    ¾²·¹µå Ç® ȤÀº ÇÁ·Î¼¼½º Ç® ±â¹ÝÀÇ °æ¿ì ¼ÒÄÏÀ» Àü´ÞÇϱâ À§Çؼ­ ²Ï³ª º¹ÀâÇÑ °úÁ¤À» °ÅÃÄ¾ß ÇÏ´Â °Í¿¡ ºñÇÏ¸é ¸Å¿ì °£´ÜÇÏ°Ô ¼ÒÄÏÀ̺¥Æ®ÀÇ Ã³¸®°¡ °¡´ÉÇÏ´Ù.

  3. ¸î¸îÀÇ ¼­¹ö´Â ÇÁ·Î¼¼½º(¾²·¹µå) Ç®°ú select(2)µîÀ» µ¿½Ã¿¡ »ç¿ëÇÑ´Ù. ´ë°³ÀÇ °æ¿ì ÀÌ·¯ÇÑ ÇÁ·Î¼¼½º(¾²·¹µå)Ç®°ú select(2)ÀÇ »ç¿ëÀº »ó´çÇÑ ¼öÁØÀÇ ÇÁ·Î±×·¡¹Ö ´É·ÂÀ» ¿ä±¸ÇÑ´Ù.

    RTS¸¦ ÀÌ¿ëÇÒ °æ¿ì ¾²·¹µå Ç®¿¡ ÀÖ´Â °¢°¢ÀÇ ¾²·¹µå¿¡¼­ ¿©·¯°³ÀÇ ¼ÒÄÏÀ» ó¸®ÇÏ´Â °úÁ¤À» ºñ±³Á¢ ¼Õ½±°Ô ±¸ÇöÇÒ ¼ö ÀÖÀ¸¸ç, select(2)³ª poll(2)º¸´Ù ÈξÀ Àú·ÅÇÑ ºñ¿ëÀ¸·Î ±¸Çö°¡´ÉÇÏ´Ù.

ù¹øÂ° ÀåÁ¡Àº ¾²·¹µå Ç®À» »ç¿ëÇÏ°Ô µÊÀ¸·Î½á ¾ò´Â ÀåÁ¡À̰í, µÎ¹øÂ° ¼¼¹øÂ° ÀåÁ¡Àº RTS¸¦ »ç¿ëÇÏ°Ô µÊÀ¸·Î½á ¾ò´Â ÀåÁ¡µéÀÌ´Ù.


2.2.2절. ±¸Çö ÇÁ·Î½ÃÁ®

´ÙÀ½Àº ±¸ÇöÀ» À§ÇÑ ´ë·«ÀûÀÎ ÇÁ·Î¼¼½º¸¦ ³ªÅ¸³½ ½´µµÄÚµåÀÌ´Ù.

int main()
{
  accept ¾²·¹µå¸¦ »ý¼ºÇÑ´Ù.
  int k=1 ; // ¾²·¹µå ÀϷùøÈ£·Î RTS¹øÈ£¸¦ ÁöÁ¤Çϱâ À§Çؼ­ »ç¿ëÇÑ´Ù. 
  SIRTMIN¿¡ ´ëÇÑ ½Ã±×³Î ¸¶½ºÅ© ¼³Á¤

  for (ÁöÁ¤ÇÑ °¹¼ö ¸¸Å­)
  {
1.  connect(k) ¾²·¹µå¸¦ »ý¼ºÇÑ´Ù.
    k++;
  }
}

accept() ¾²·¹µå
{
  socket->bind->listen;
  ¸¸µé¾îÁø µè±â ¼ÒÄÏ¿¡ ´ëÇÏ¿© RTS¹ÝÀÀÇϵµ·Ï ÇÑ´Ù.  
  while(1)
  {
2.  accept()¸¦ ÅëÇØ¼­ ¿¬°áÀÌ ¹ß»ýÇϸé fcntlÀ» ÅëÇØ¼­ ÇØ´ç ¼ÒÄÏÀÌ 
    RTS¸¦ ¹ß»ýÇϵµ·Ï ÇÑ´Ù. 
  }
}

connect() ¾²·¹µå
{
  pthread_sigmask¸¦ ÀÌ¿ëÇØ¼­ RTS¿¡ ¾²·¹µå°¡ ¹ÝÀÀÇϵµ·Ï ÇÑ´Ù.  
  ¹ÝÀÀÇÏ´Â RTS¹øÈ£´Â ¾²·¹µå¸¶´Ù ´Ù¸£´Ù. 
  ù¹øÂ° »ý¼ºµÈ ¾²·¹µå´Â SIGRTMIN+1, ±×´ÙÀ½Àº SIGRTMIN+2.. ½ÄÀÌ´Ù.
  while(1)
  {
    sigwaitinfo()¸¦ ÀÌ¿ëÇØ¼­ RTS¸¦ ±â´Ù¸°´Ù.   
    RTS°¡ ¹ß»ýÇÏ¸é ¼ÒÄÏÁöÁ¤ÀÚ¸¦ ÅëÇØ¼­ Ŭ¶óÀÌ¾ðÆ®¿Í Åë½ÅÇÑ´Ù.  
  }
}
				

  1. connect()¾²·¹µå¸¦ »ý¼ºÇÒ¶§ °¢ ¾²·¹µå´Â °íÀ¯ÀÇ ÀϷùøÈ£¸¦ °¡Áö¸ç ÀÌ ÀϷùøÈ£´Â ¾²·¹µå°¡ ¹ÝÀÀÇÒ RTS¹øÈ£¸¦ ÇÒ´ç¹Þ±â À§Çؼ­ »ç¿ëÇÑ´Ù. ¿¹¸¦ µé¾î ù¹øÂ° ¾²·¹µå´Â 1ÀÌ ÀÎÀÚ·Î ³Ñ¾î°¡¹Ç·Î ÀÌ ¾²·¹µå´Â SIGRTMIN+1¿¡ ´ëÇØ¼­ ¹ÝÀÀÇÑ´Ù. µÎ¹øÂ° ¾²·¹µå´Â SIGRTMIN+2¿¡ ´ëÇØ¼­ ¹ÝÀÀÇÑ´Ù.

  2. °¢ ¾²·¹µå°¡ ¹ÝÀÀÇØ¾ßµÉ RTS¹øÈ£¿¡ ´ëÇØ¼­ ÁöÁ¤À» ÇßÀ¸¹Ç·Î ÀÌÁ¦ accept()¾²·¹µå¸¦ ÅëÇØ¼­ ¸¸µé¾îÁø ¿¬°á ¼ÒÄÏÀÌ Àû´çÇÑ RTS¹øÈ£·Î ½Ã±×³ÎÀ» ¹ß»ý½Ã۵µ·Ï ÇÏ¸é µÉ°ÍÀÌ´Ù. ÀÌÀÛ¾÷Àº fcntl(2)À» ÅëÇØ¼­ ÀÌ·ç¾îÁö¸ç, ¸¸¾à fcntlÀ» ÀÌ¿ëÇØ¼­ SIGRTMIN+1½Ã±×³ÎÀ» ¹ß»ýÇϵµ·Ï ¿¬°á ¼ÒÄÏÀ» ¼³Á¤ÇÑ´Ù¸é, ¾ÕÀ¸·Î ÀÌ ¼ÒÄÏ¿¡ µ¥ÀÌÅÍ À̺¥Æ®°¡ ¹ß»ýÇϸé SIGRTMIN+1ÀÌ ¹ß»ýÇÒ °ÍÀ̸ç ÀÚµ¿ÀûÀ¸·Î ù¹øÂ° connect()¾²·¹µå·Î ½Ã±×³ÎÀÌ Àü´ÞµÉ °ÍÀÌ´Ù.

  3. connect()·Î ½Ã±×³ÎÀÌ Àü´ÞµÈ´Ù¸é, ¾²·¹µå´Â sigwaitinfo()¸¦ ÅëÇØ¼­ RTSÁ¤º¸¸¦ ¾ò¾î¿Ã ¼ö ÀÖÀ¸¸ç, À̺¥Æ®°¡ ¹ß»ýÇÑ ¼ÒÄÏÀ» ÅëÇÏ¿© µ¥ÀÌÅÍ Åë½ÅÀ» ÇÏ¸é µÈ´Ù. connect()¾²·¹µå°¡ ¿©·¯°³ÀÇ ¼ÒÄÏÀ» °ü¸®Çϰí ÀÖ´Ù°í ÇÏ´õ¶óµµ sigwaitinfo()¸¦ ÀÌ¿ëÇØ¼­ À̺¥Æ®°¡ ¹ß»ýÇÑ ¼ÒÄÏ¿¡ ´ëÇÑ Á¤º¸¸¦ ¾ò¾î ¿Ã ¼ö ÀÖÀ¸¹Ç·Î ½±°Ô ¿©·¯°³ÀÇ ¼ÒÄϰü¸®°¡ °¡´ÉÇÏ´Ù.

¾²·¹µå Ç®À» ÀÛ¼ºÇÏ´Â ÀÌÀ¯´Â ³×Æ®¿öÅ© 󸮸¦ °¢°¢ÀÇ ¾²·¹µå·Î ºÐ»ê½Ã۱â À§ÇÑ ¸ñÀûÀÌ´Ù. ¿©±â¿¡¼­ÀÇ ·Îµå¹ë·±½ÌÀº ´Ü¼øÈ÷ ÇϳªÀÇ ¾²·¹µå°¡ ¸î°³ÀÇ Å¬¶óÀÌ¾ðÆ®¸¦ °ü¸®ÇÏ´ÂÁö¸¦ °Ë»çÇØ¼­ °¡Àå ÀûÀº Ŭ¶óÀÌ¾ðÆ®¸¦ ó¸®Çϰí ÀÖ´Â ¾²·¹µå¿¡ ¼ÒÄÏ¿¡ ´ëÇÑ Ã³¸®¸¦ ³Ñ±â´Â °£´ÜÇÑ ¹æ½ÄÀ» »ç¿ëÇÑ´Ù. ÀÌ·¯ÇÑ Ã³¸®¸¦ À§Çؼ­ °¢°¢ÀÇ ¾²·¹µå°¡ ¸î°³ÀÇ ¼ÒÄÏÀ» ó¸®Çϰí ÀÖ´ÂÁö¿¡ ´ëÇÑ Á¤º¸¸¦ À¯ÁöÇϰí ÀÖ¾î¾ß ÇÑ´Ù. ´ÙÀ½Àº ¾²·¹µå ¼ÒÄÏ ºÐ¹è¸¦ À§ÇÑ ÀÚ·á ±¸Á¶´Ù.

typedf struct _fd_sig
{
   int signum;
   int pid;
} fd_sig;

multimap<int, fd_sig> pool_list;
				
pool_list´Â multimapÀ¸·Î ±¸¼ºµÈ´Ù. key°ªÀº ¾²·¹µå¿¡¼­ ó¸®ÁßÀÎ ¼ÒÄÏÀÇ °¹¼ö¸¦ ³ªÅ¸³½´Ù. value´Â fd_sig±¸Á¶Ã¼ÀÌ´Ù. fd_sig±¸Á¶Ã¼ÀÇ ¸â¹öº¯¼öÀÎ signumÀº RTS½Ã±×³Î ¹øÈ£À̸ç, µ¿½Ã¿¡ ¾²·¹µå¸¦ ÁöÁ¤Çϱâ À§ÇÑ ¹øÈ£·Îµµ »ç¿ëµÈ´Ù. pid´Â ÆÄÀÏ(¼ÒÄÏ)¿¡ À̺¥Æ®°¡ ¹ß»ýÇßÀ» ¶§ À̺¥Æ® Å뺸¸¦ ¹Þ°ÔµÉ ¾²·¹µåÀÇ pid·Î fcntl()À» ÅëÇØ¼­ ½Ã±×³ÎÀ» Àü´Þ¹ÞÀ» ¾²·¹µå¸¦ ÁöÁ¤Çϱâ À§Çؼ­ »ç¿ëµÈ´Ù. ¾Æ½Ã´Ù½ÃÇÇ ¸®´ª½º¿¡¼­ÀÇ ¾²·¹µå´Â clone(2)È£ÃâÀ» ÅëÇÑ ÇÁ·Î¼¼½º°³³äÀ¸·Î ÀÛµ¿µÇ±â ¶§¹®¿¡ ¹Ýµå½Ã °¢ ¾²·¹µåº° pid¸¦ ±¸ºÐÇØÁà¾ß ÇÑ´Ù.

참고: ¼Ö¶ó¸®½º °°Àº °æ¿ì ¿ÏÀüÇÑ ¾²·¹µå¸¦ Áö¿øÇϹǷΠ¸ðµç ¾²·¹µå°¡ µ¿ÀÏÇÑ pid¸¦ °¡Áö°Ô µÈ´Ù ±×·¯¹Ç·Î ±»ÀÌ °¢ ¾²·¹µåÀÇ pid¸¦ ³Ñ°ÜÁÙ ÇÊ¿ä ¾øÀÌ ÇÊ¿äÇÒ¶§ getpid(2)¸¸ È£ÃâÇÏ¸é µÈ´Ù.

¸®´ª½ºµµ ÃÖ±Ù Ä¿³Î 2.4.20 ¿¡¼­´Â ÇϳªÀÇ pid¸¸À¸·Î »ý¼ºµÇ´Â°É È®ÀÎÇß´Ù. ÀÚ¼¼ÇÑ Ä¿³Î¹®¼­¸¦ ÀÐ¾î º¸Áö ¾Ê¾Æ¼­ È®½ÅÇÒ ¼ö´Â ¾øÁö¸¸ ¸®´ª½ºµµ clone()À» »ç¿ëÇÏÁö ¾Ê´Â ¿ÏÀüÇÑ ¾²·¹µå¸¦ Áö¿øÇÏ´Â °ÍÀ¸·Î º¸ÀδÙ. ÀÌ·¯ÇÑ ÃֽЏ®´ª½º Ä¿³Î¿¡¼­ÀÇ °æ¿ì getpid()¸¸À» ÀÌ¿ëÇØµµ °ü°è¾øÀÌ ÀÛµ¿ µÇ¾ú´Ù.

±×·¯³ª Unix¿Í ¸®´ª½º ±×¸®°í ¸®´ª½º Ä¿³Î¹öÁ¯°£ ȣȯÀ» À¯ÁöÇÏ±æ ¿øÇÑ´Ù¸é ¾²·¹µåº° PID¸¦ Àоî¿Í¼­ ÀÛ¾÷ÇÏ´Â °ÍÀ» ÃßõÇÑ´Ù.

fd_sig lfd_sig;
for (i = 0, k=1; i < thread_num; i++, k++)
{
  // º¯¼ö k´Â ¾²·¹µå°¡ ±â´Ù¸± ½Ã±×³ÎÀÇ ¹øÈ£ÀÌ´Ù. 
  // (SIGRTMIN+k)Çü½ÄÀ¸·Î »ç¿ëµÈ´Ù.  
  pthread_create(&th_t, NULL, thread_func, (void *)&k);
  lfd_sig.signum = (k);
  lfd_sig.pid    = pid; // pthread_create¸¦ ÅëÇØ¼­ »ý¼ºµÈ ¾²·¹µåÀÇ pid 
  pool_list.insert(pair<int, fd_sig>(0, lfd_sig));
}
				
accept()°¡ ¹ß»ýÇØ¼­ ¿¬°á ¼ÒÄÏÀÌ ¸¸µé¾îÁö¸é pool_listÄÁÅ×À̳ÊÀÇ Ã¹¹øÂ° µ¥ÀÌÅ͸¦ °¡Á®¿ÂÈÄ ÇØ´ç key¸¦ +1 Áõ°¡½ÃÄÑÁÖ°í ¿¬°á ¼ÒÄÏ¿¡ ´ëÇØ¼­´Â fcntl()À» ÀÌ¿ëÇØ¼­ SIGRTMIN+fd_sig.signum ½Ã±×³ÎÀ» ¹ß»ý½Ã۵µ·Ï ¼¼ÆÃÇÏ¸é µÈ´Ù. ¸ÖƼ¸ÊÀº ¿À¸§Â÷¼øÀ¸·Î Á¤·ÄÀÌ µÇ¹Ç·Î ¿ì¸®´Â ¾ðÁ¦³ª °¡Àå ÀûÀº ¼ÒÄÏÀ» ó¸®ÇÏ´Â ¾²·¹µå¿¡ ¼ÒÄÏ󸮸¦ À§ÀÓ ÇÒ°ÍÀ̶ó´Â°É º¸ÁõÇÒ ¼ö ÀְԵȴÙ. ¼ÒÄÏ¿¬°áÀÌ Á¾·áµÇ°Å³ª ¾î¶² ÀÌÀ¯·Î ²÷°åÀ» °æ¿ì¿¡´Â k-1À» ÇÏ¸é µÈ´Ù. ¼ÒÄÏÀÌ Á¾·áµÇ¾úÀ» °æ¿ì¿¡´Â Á¾·áµÈ ¼ÒÄÏÀ» ó¸®ÇÏ´Â ÄÁÅ×ÀÌ³Ê ¸â¹öµ¥ÀÌÅ͸¦ ã¾Æ³»¾ß ÇϹǷΠpool_list ÄÁÅ×À̳ʸ¦ ¼øÈ¯Çϸ鼭 fd_sig.signum°ú ¾²·¹µå¹øÈ£°¡ ÀÏÄ¡ÇÏ´Â ¸â¹ö¸¦ ã¾Æ³»¾ß ÇÑ´Ù.

참고: ¿©±â¿¡¼­´Â ¼³¸íÀÇ ÆíÀǸ¦ À§Çؼ­ key+1ÇÑ´Ù°í Çߴµ¥, ¸ÖƼ¸Ê¿¡¼­ ŰÀÇ °ªÀº º¯°æºÒ°¡´É ÇÏ´Ù. ±×·¯¹Ç·Î ½ÇÁ¦·Î »ðÀÔÈÄ »èÁ¦ ÇÏ´Â °úÁ¤ÀÌ ÇÊ¿äÇÏ´Ù.

À§ÀÇ ÀڷᱸÁ¶´Â ¹°·Ð È¿À²¼ºµîÀ» °í·ÁÇÑ°Ç ¾Æ´Ï´Ù. ´ÜÁö ÆíÀǼº¸¸À» °í·ÁÇÑ °ÍÀÌ´Ï ¸¶À½¿¡ µéÁö ¾Ê´Â´Ù¸é Àû´çÇÑ ÀڷᱸÁ¶¸¦ ¸¸µé¾î¼­ »ç¿ëÇϱ⠹ٶõ´Ù. º¸Åë ¾²·¹µå Ç®À» ±¸¼ºÇÑ´Ù°í ÇÏ¸é ¾Æ¸¶µµ 20°³ ÀÌ»óÀÇ ¾²·¹µå¸¦ »ý¼ºÇؼ­ »ç¿ëÇÏ´Â °æ¿ì´Â ¸Å¿ì µå¹° °ÍÀ̹ǷÎ, ´ÜÁö ¹è¿­·Î ¸¸µé¾î¼­ ºñ±³ÇÏ´Â ¹æ½ÄÀ» »ç¿ëÇØµµ º° ¹®Á¦´Â ¾øÀ» °ÍÀÌ´Ù.



2.2.3절. ½ÇÁ¦ ±¸Çö

ÀÌ·¯ÇÑ ³×Æ®¿öÅ© ÇÁ·Î±×·¥ ±¸ÇöÀ» À§ÇÑ ¿©·¯°¡Áö °³¹ß¹æ¹ýµé ÀÚü°¡ "À̰ŴÙ"¶ó°í Á¤ÇØÁø°Ô ¾øÀÌ È¯°æ°ú Çʿ信 µû¶ó ´Þ¶óÁö±â ¶§¹®¿¡ ´ÜÁö ¿¹Á¦Äڵ常 ´Þ¶û ¼³¸íÇØ¼­´Â ³Ê¹« °æÁ÷µÉ ¼ö°¡ ÀÖ´Ù. ÀÌ·± ÀÌÀ¯·Î ´ÜÁö ¿¹Á¦ ¼ÀÇø¸ º¸¿©ÁÖ´Â°Ô ¾Æ´Ñ ±âŸ ÀÌ·± Àú·± ¾ÆÀ̵ð¾óÇÑ ³»¿ë±îÁö ´ã°Ô µÇ¾ú´Ù. Áö·çÇß´õ¶óµµ ÀÌÇØÇØ ÁÖ±æ ¹Ù¶ó¸é¼­ ´ÙÀ½ÀÇ ¿¹Á¦¸¦ ºÐ¼®Çϰí Å×½ºÆ® ÇØº¸±â ¹Ù¶õ´Ù.

¿¹Á¦ : rts_poll.cc

#include <pthread.h>
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <vector>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <map>

#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <fcntl.h>

using namespace std;

pthread_mutex_t mutex_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t sync_cond  = PTHREAD_COND_INITIALIZER;

int gpid;
typedef struct _fd_sig
{
    int signum;
    int pid;
} fd_sig;

/*
 * 1
 * ¾²·¹µå´ç ó¸®ÁßÀÎ ¼ÒÄÏÀÇ Á¤º¸¸¦ À¯ÁöÇϱâ 
 * À§ÇÑ ÀڷᱸÁ¶. 
 * key   : ó¸®ÁßÀÎ ¼ÒÄÏÀÇ ¼ö 
 * value : ¾²·¹µå(RTS Á¤º¸)
 */
multimap<int, fd_sig> pool_list;
multimap<int, fd_sig>::iterator mi; 

// RTS overflow°¡ ¹ß»ýÇßÀ» ¶§ ½ÇÇàµÇ´Â Çڵ鷯
void do_sigio(int signo)
{
    printf("SIGIO : RTS signal queue overflow\n");    
}

/* 
 * ±âº» ½Ã±×³Î ÇÚµé·Î ÃʱâÈ­ ¹× µî·Ï
 * ¿©±â¿¡¼­´Â RTS overflowÀÇ Ã³¸®¸¦ À§ÇÑ ½Ã±×³Î 
 * Çڵ鷯¸¦ µî·ÏÇÑ´Ù.  
 */
void init_signal_handler()
{
    struct sigaction sigact;
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags        = SA_SIGINFO;
    sigact.sa_restorer    = NULL;
    sigact.sa_handler    = do_sigio;
    if (sigaction(SIGIO, &sigact, NULL) < 0)
    {
        perror("sigaction SIGIO ");
        exit(0);
    }

    return ;
}

/*
 * 2
 * ÀÎÀÚ·Î ÁÖ¾îÁö´Â ¼ÒÄÏÁöÁ¤ÀÚ fd°¡ RTS½Ã±×³ÎÀ»
 * ¹ß»ýÇϵµ·Ï ¼³Á¤ÇÑ´Ù. 
 * ¹ß»ý½ÃŰ´Â RTS½Ã±×³Î ¹øÈ£´Â sig_num¿¡ ÀÇÇØ¼­ 
 * °áÁ¤µÈ´Ù. 
 */
int setup_sigio(int fd, int sig_num, int pid)
{
    if (fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC) < 0)
    {
        perror("fcntl NONBLOCK ");
        return -1;
    }
    if (fcntl(fd, F_SETSIG, SIGRTMIN+sig_num) < 0)
    {
        perror("fcntl SETSIG "); 
        return -1;
    }

    // ÀÎÀÚ·Î ÁÖ¾îÁø ÆÄÀÏÁöÁ¤ÀÚ fd¿¡¼­ À̺¥Æ®°¡ ¹ß»ýÇÒ °æ¿ì  
    // pid¸¦ °¡Áö´Â ¾²·¹µå·Î RTS SIGRTMIN+sig_num ½Ã±×³ÎÀÌ Àü´ÞµÈ´Ù.  
    if (fcntl(fd, F_SETOWN, pid) < 0)
    {
        perror("fcntl SETOWN ");
        return -1;
    }
    return 0;
}

/*
 * 3 
 * µè±â ¼ÒÄÏÀ» ¸¸µé°í 
 * ¿¬°áÀ» ±â´Ù¸°´Ù. 
 * ¸¸¾à ¿¬°áÀÌ µé¾î¿Â´Ù¸é pool_listÀڷᱸÁ¶¸¦ ÅëÇØ¼­ 
 * °¡Àå ÀûÀº ¼ÒÄÏÀ» ó¸®ÇÏ´Â ¾²·¹µå¸¦ ¾Ë¾Æ¿À°í 
 * ±× ¾²·¹µå¿¡ ÇØ´çµÇ´Â RTS½Ã±×³Î ¹øÈ£·Î RTS½Ã±×³ÎÀ» 
 * ¹ß»ýÇϵµ·Ï ¼ÒÄÏÀ» ¼³Á¤ÇÑ´Ù.  
 */
void *accept_listener(void *data)
{
    int server_sockfd, cli_sockfd;    
    fd_sig lfd_sig;
    int count;
    sigset_t set;
    int client_sockfd;
    socklen_t clilen;
    int ret;

    int signum = *((int *)data);
    struct sockaddr_in serveraddr, clientaddr;
    struct siginfo si;

    if ((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket error ");
        exit(0);
    }

    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family        = AF_INET;
    serveraddr.sin_addr.s_addr    = htonl(INADDR_ANY);
    serveraddr.sin_port            = htons(1234);

    if (bind (server_sockfd, (struct sockaddr *)&serveraddr, 
            sizeof(serveraddr)) == -1)
    {
        perror("bind error ");
        exit(0);
    }

    if (listen(server_sockfd, 5) == -1)
    {
        perror("listen error ");
        exit(0);
    }
    if (setup_sigio(server_sockfd, signum, getpid()) == -1) 
    {
        printf("sigio error\n");
        exit(0);
    }

    sigemptyset(&set);
    sigaddset(&set, SIGRTMIN+signum);
    sigprocmask(SIG_BLOCK, &set, NULL);

    pthread_mutex_lock(&mutex_lock);
    pthread_cond_signal(&sync_cond);
    pthread_mutex_unlock(&mutex_lock);

    while(1)
    {
        int ret;
        ret = sigwaitinfo(&set, &si);
        if (ret == SIGRTMIN+signum)
        {
            if (si.si_fd == server_sockfd) 
            {
                cli_sockfd = accept(server_sockfd, 
                                (struct sockaddr *)&clientaddr,
                                &clilen);
                if(cli_sockfd < 0)
                {
                    printf("Accept error\n");
                    continue;
                }
                mi = pool_list.begin();
                lfd_sig = mi->second;
                count = mi->first+1;

                /*
                 * ¿¬°á¼ÒÄÏ¿¡ ´ëÇØ¼­ SIGRTMIN+signum RTS¸¦ ¹ß»ýÇϵµ·Ï 
                 * ¼³Á¤ÇÑ´Ù. 
                 * fcntl()À» À§Çؼ­ pid¸¦ ³Ñ±â´Â°É ÁÖ¸ñÇϱ⠹ٶõ´Ù.  
                 */
                cout << "Accept " << cli_sockfd << " : " 
                    << mi->second.signum << " : " 
                    << mi->second.pid << endl;
                setup_sigio(cli_sockfd, mi->second.signum, mi->second.pid);
                pool_list.erase(mi);
                pool_list.insert(pair<int, fd_sig>(count, lfd_sig));
            }
            else
            {
            }
        }
    }
}

/*
 * Ŭ¶óÀÌ¾ðÆ®¿Í µ¥ÀÌÅ͸¦ ÁÖ°í ¹ÞÀ» ¾²·¹µå ÇÔ¼öÀÌ´Ù. 
 * Ŭ¶óÀÌ¾ðÆ®·Î ºÎÅÍ ÀÐÀº µ¥ÀÌÅ͸¦ ¹ÝÇâ(echo)ÇÑ´Ù. 
 */
void *jecho(void *rts_num)
{

    int signum = *((int *)rts_num);
    int ret; 
    socklen_t clen;
    char buf[256];
    struct sockaddr_in cname;
    int n;

    // ¾²·¹µåÀÇ PID¸¦ ¾ò¾î¿Â´Ù.     
    gpid = getpid(); 

    sigset_t set;

    sigemptyset(&set);
    sigaddset(&set, SIGRTMIN+signum);
    pthread_sigmask(SIG_BLOCK, &set, NULL);

    pthread_mutex_lock(&mutex_lock);
    pthread_cond_signal(&sync_cond);
    pthread_mutex_unlock(&mutex_lock);

    struct siginfo si;
    fd_sig lfd_sig;
    int count;
    int lpid;

    while(1)
    {
        clen = sizeof(cname);
        ret = sigwaitinfo(&set, &si);
        memset(buf,0x00, 256); 
        if (ret == SIGRTMIN+signum)
        {
            if ((n = read (si.si_fd, buf, 255)) <= 0)
            {
                printf("read error \n");
                close(si.si_fd);
                mi = pool_list.begin();
                while(mi != pool_list.end())
                {
                    if (mi->second.signum == signum)
                    {
                        lfd_sig = mi->second;
                        count = mi->first - 1;
                        pool_list.erase(mi);
                        pool_list.insert(pair<int, fd_sig>(count, lfd_sig));
                    }
                    *mi++;
                }
            }    
            else
            {
                getsockname(si.si_fd, (struct sockaddr *)&cname, &clen);
                printf("%s(%d) : %s", inet_ntoa(cname.sin_addr), signum, buf);
                write(si.si_fd, buf, strlen(buf));
            }
        }
        else
        {
        }
    }
}

int main(int argc, char **argv)
{
    struct siginfo si;
    int status;
    int k;
    fd_sig lfd_sig;
    sigset_t set;
    unsigned int i;

    if (argc !=2 )
    {
        printf("Usage : ./rts_th [thread num]\n");
        exit(1);
    }
    int thread_num = atoi(argv[1]);
    vector<void *(*)(void *)> thread_list;
    vector<pthread_t> tident(thread_num);
    pthread_attr_t myattr;
    init_signal_handler();

    sigemptyset(&set);
    sigaddset(&set, SIGRTMIN);
    sigprocmask(SIG_BLOCK,&set, NULL);

    thread_list.push_back(accept_listener);
    for (i = 0; i < thread_num; i++) 
    {    
        thread_list.push_back(jecho);
    }

    /*
     * ¾²·¹µå¸¦ »ý¼ºÇÑ´Ù.  
     * ù¹øÂ° ¾²·¹µå´Â accept()Àü¿ë ¾²·¹µåÀ̸ç
     * ÀÌÈÄ »ý¼ºµÇ´Â ¾²·¹µå°¡ Ŭ¶óÀÌ¾ðÆ® Åë½ÅÀü¿ë ¾²·¹µåÀÌ´Ù. 
     * ¾²·¹µå¸¦ »ý¼ºÇÒ¶§ ³Ñ¾î°¡´Â ÀÎÀÚ K´Â ¾²·¹µå°¡ ±â´Ù¸± 
     * RTS ½Ã±×³Î ¹øÈ£ÀÌ´Ù. 
     * °¢ ¾²·¹µå´Â SIGRTSMIN+k ¹øÈ£¸¦ °¡Áö´Â RTS¸¦ ±â´Ù¸®°ÔµÈ´Ù.  
     */    
    for (i = 0, k = 1; i < thread_list.size(); i++, k++)
    {
        /*
         * ¸ÞÀÎ ¾²·¹µå¿Í »ý¼ºµÇ´Â ¾²·¹µå°£¿¡ Á¤È®ÇÑ µ¥ÀÌÅÍ 
         * Àü´ÞÀÌ ÇÊ¿äÇϹǷΠ¹ÂÅØ½º¿Í Á¶°Çº¯¼ö¸¦ ÀÌ¿ëÇØ¼­  
         * ¾²·¹µå µ¿±âÈ­¸¦ ½ÃÄÑÁØ´Ù.
         */
        pthread_mutex_lock(&mutex_lock);
        pthread_create(&tident[i], NULL, thread_list[i], (void *)&k);

        /*
         * ¾²·¹µå ÀڷᱸÁ¶
         * °¢ ¾²·¹µå¿¡¼­ ó¸®ÇÏ´Â RTS¹øÈ£¿Í ó¸®ÁßÀÎ ¼ÒÄÏÀÇ °¹¼ö¸¦
         * À¯ÁöÇÑ´Ù. 
         */
        lfd_sig.signum = k;  
        pthread_cond_wait(&sync_cond, &mutex_lock);
        lfd_sig.pid    = gpid;
        if (i !=0)
            pool_list.insert(pair<int, fd_sig>(0, lfd_sig));
        pthread_mutex_unlock(&mutex_lock);
    }

    cout << "Thread Join " << endl;
    for (i = 0; i < thread_list.size(); i++)
    {
        pthread_join(tident[i], (void **)&status);
    }
    return 1;
}
				
¾²·¹µå, ÇÁ·Î¼¼½º, ½Ã±×³Î¿¡ ´ëÇÑ ³»¿ëÀ» ÀÌÇØÇϰí ÀÖ´Ù¸é ÀÌÇØÇϱ⿡ ¾î·Á¿î ºÎºÐÀÌ ¾øÀ» °ÍÀÌ´Ù. ÄÚµå´Â ÃÖ¼ÒÇÑÀÇ ¿¡·¯Ã³¸®¸¸ ½Å°æ½èÀ¸¸ç È¿À²,À¯Áöº¸¼ö °°Àº °Íµé ¿ª½Ã ½Å°æ¾²Áö ¾Ê¾Ò´Ù.


3절. °á·Ð

ÀÌ»ó RTS¿Í ¾²·¹µåÇ®°£ÀÇ Á¶ÇÕ¿¡ ´ëÇØ¼­ ¾Ë¾Æº¸¾Ò´Ù. ¾Æ¸¶µµ ²Ï Èï¹ÌÀÖ´Â ³»¿ëÀÌ µÇ¾úÀ¸¸®¶ó°í »ý°¢µÈ´Ù. À̹ø¿¡ ´Ù·ç¾ú´ø ÁÖÁ¦¿¡ ´ëÇØ¼­´Â ¾ÆÁ÷µµ °í¹ÎÇØ¾ßµÉ ºÎºÐÀÌ ¸¹ÀÌ ÀÖÀ¸¹Ç·Î Æ´Æ´È÷ ´õ È¿À²ÀûÀÌ°í ±ò²ûÇÑ ¹æ¹ý¿¡ ´ëÇØ¼­ °í¹ÎÇØ º¸µµ·Ï ÇÏÀÚ..


Cache Error
EmailÀ» ±âÀÔÇϸé, ´ñ±ÛÀÌ ¸ÞÀÏ·Î Àü´ÞµË´Ï´Ù.