ÇÔ¼öÇü ÇÁ·Î±×·¡¹Ö F#
¿¹Ãø °¡´ÉÇÑ ¼öÇÐÀû ÇÔ¼ö ±¸ÇöÇϱâ
¡®º¯°æ ºÒ°¡´É¼º(Immutability)¡¯Àº ÇÔ¼öÇü ¾ð¾îÀÇ ÇÙ½É °³³äÀÌ´Ù. µ¥ÀÌÅ͸¦ º¯°æÇÏÁö ¾ÊÀ½À¸·Î½á ¸í·ÉÇü ¾ð¾î¿¡ ºñÇØ Á» ´õ ½±°Ô ¿¹Ãø °¡´ÉÇÑ ÇÔ¼ö¸¦ ±¸ÇöÇÒ ¼ö ÀÖ´Ù. À̹ø ½Ã°£¿¡´Â ÂüÁ¶ Åõ¸í¼º(Referential Transparency)°ú ºÎÀÛ¿ë(Side-Effect) ±×¸®°í ¼ø¼ö ÇÔ¼ö(Pure Function)ÀÇ °³³äÀ» »ìÆìº¸°í, ¼öÇÐÀû ÇÔ¼ö·Î ÀÎÇÑ ÃÖÀûÈ¿Í µ¥ÀÌÅÍ ·¹À̽º, µ¥µå¶ôÀ» Á¦°ÅÇÏ´Â ¹æ¹ýÀ» ¼Ò°³ÇÑ´Ù.
¿¹Ãø °¡´ÉÇÑ(Predictable) Äڵ带 ÀÛ¼ºÇÑ´Ù´Â °ÍÀº ¹«¾ùÀ» ÀǹÌÇÒ±î? ±×¸®°í ¿Ö ÇÊ¿äÇÒ±î? ±¹¸³±¹¾î¿ø Ç¥Áر¹¾î´ë»çÀüÀº ¡®¿¹Ãø(çãö´)¡¯ÀÇ ¶æÀ» ¡°¹Ì¸® Çì¾Æ·Á ÁüÀÛÇÔ¡±À̶ó°í ±â¼úÇϰí ÀÖ´Ù. ºñ½ÁÇÑ ¸»·Î´Â ¿¹»ó, ¿¹°ß, ÁüÀÛ, ÃßÃø, Ã߸®, Áö·¹ÁüÀÛ µîÀÌ ÀÖ´Ù. ¿ì¼± Áß¾Ó Ã³¸® ÀåÄ¡(Central Processing Unit, ÀÌÇÏ CPU)ÀÇ ÀÔÀå¿¡¼ ¿¹ÃøÀ» »ìÆìº¸ÀÚ. CPU¿¡´Â ¿¹Ãø°ú °ü·ÃµÈ ´ëÇ¥ÀûÀÎ ±â¼ú Áß Çϳª·Î ¡®ºÐ±â ¿¹Ãø(Branch Prediction)¡¯ÀÌ ÀÖ´Ù. ¿ä¾àÇÏ¸é ºÐ±â ¿¹ÃøÀº ´ÙÀ½ ºÐ±â¸¦ ¿¹ÃøÇÏ´Â °ÍÀÌ´Ù. ¿Ö ´ÙÀ½ ºÐ±â¸¦ ¿¹ÃøÇÒ±î? ÀÌ Áú¹®¿¡ ´ëÇÑ ´äº¯Àº ¸Å¿ì ´Ü¼øÇÏ´Ù. CPUÀÇ °í¼Óȸ¦ À§Çؼ´Ù.
CPU¿¡´Â Á¶°Ç ºÐ±â ¸í·ÉÀÌ Àִµ¥, ÀÌ´Â ºÐ±â·Î ÀÎÇØ ¸í·É¾î ÆÄÀÌÇÁ¶óÀÎÀÌ ÀϽÃÀûÀ¸·Î Á¤ÁöµÇ´Â »óȲÀ» Á¦°ÅÇÔÀ¸·Î½á ¼º´ÉÀ» Çâ»óÇÏ´Â °ÍÀÌ´Ù. ºÐ±â ¿¹ÃøÀº ÇØ´ç Á¶°Ç ºÐ±â¹®ÀÌ ºÐ±âÇÑ ÀÌ·ÂÀ̳ª ·çÇÁ ±¸Á¶, ÇÔ¼ö ±¸Á¶ µîÀÇ Á¤º¸¸¦ ±â¹ÝÀ¸·Î ¼öÇàÇÑ´Ù. ±× ¶§¹®¿¡ ºÐ±â ¿¹ÃøÀÌ Ç×»ó Á¤È®ÇÑ °ÍÀº ¾Æ´Ï´Ù. À̹ø¿¡´Â ÄÚµå ÀÔÀå¿¡¼ ¿¹ÃøÀ» »ìÆìº¸ÀÚ.
<¸®½ºÆ® 1> PlusOne ÇÔ¼ö
int PlusOne(int value)
{
return value + 1;
}
<¸®½ºÆ® 1>°ú °°ÀÌ PlusOneÀÌ ±¸ÇöµÅ ÀÖ´Ù¸é PlusOne ÇÔ¼öÀÇ ÀÔ·Â °ª value°¡ 2015ÀÏ ¶§ È£Ãâ ¼ø¼³ª ¿ÜºÎ ȯ°æ°ú »ó°ü¾øÀÌ Ç×»ó °°Àº °á°ú °ª 2016À» µ¹·ÁÁÖ°Ô µÈ´Ù. ÀÌ·¯ÇÑ ¼ºÁúÀ» ´ÙÀ½°ú °°ÀÌ Á¤ÀÇÇÒ ¼ö ÀÖ´Ù.
¡°ÇÔ¼öÀÇ ÀÎÀÚ value °ªÀÌ º¯ÇÏÁö ¾Ê´Â´Ù¸é PlusOne ÇÔ¼ö´Â Ç×»ó °°Àº °á°ú¸¦ µ¹·ÁÁØ´Ù.¡±
ÀÌ Á¤ÀǸ¦ Ȱ¿ëÇÏ¸é ¡®PlusOne(2015) = PlusOne(2000 + 15) = 2016¡¯ÀÌ ¼º¸³ÇÏ°Ô µÈ´Ù. value·Î Àü´ÞµÈ °ª 2015¿Í 2000 + 15°¡ °°±â ¶§¹®ÀÌ´Ù. À̸¦ Á» ´õ Ȱ¿ëÇÏ¸é ¡®(PlusOne(2015) - PlusOne (2015)) = 0¡¯µµ ¿ª½Ã ¼º¸³ÇÏ°Ô µÈ´Ù.
<¸®½ºÆ® 2> ÃÖÀûÈ Àü
int result = PlusOne(x) + PlusOne(x) * (PlusOne(x) ? PlusOne(x));
<¸®½ºÆ® 2>¸¦ ¾Õ¼ »ìÆìº» °³³äÀ¸·Î Á¢±ÙÇØ º¸ÀÚ. ¿ì¼± ¡®int result = PlusOne(x) + PlusOne(x) * (PlusOne(x) - PlusOne(x));¡¯¿¡¼ ¡®PlusOne(x) = PlusOne(x)¡¯°¡ ¼º¸³ÇÑ´Ù¸é ¡®PlusOne(x) ? PlusOne(x)¡¯´Â 0ÀÌ µÉ °ÍÀÌ´Ù. ±×·¸´Ù¸é ¡¯PlusOne(x) ? PlusOne(x)¡¯¸¦ ¡®0¡¯À¸·Î ¹Ù²ãµµ Àüü ±¸¹®¿¡ Àǹ̰¡ º¯ÇÏÁö ¾Ê´Â´Ù. ÀÌÁ¦ Àüü ±¸¹®Àº ¡®int result = PlusOne(x) + PlusOne(x) * (0);¡¯À¸·Î º¯°æÇÒ ¼ö ÀÖ´Ù.
º¯°æµÈ Äڵ忡¼ ¡®PlusOne(x) * (0)¡¯Àº ¼öÇÐÀû »ó½ÄÀ» °í·ÁÇÒ ¶§ ´ç¿¬È÷ 0À¸·Î º¯°æÇÒ ¼ö ÀÖ´Ù. À̸¦ ´Ù½Ã Àû¿ëÇÏ¸é ¡®int result = PlusOne(x) + 0;¡¯ÀÌ µÈ´Ù. °á±¹ ¡®int result = PlusOne(x);¡¯·Î º¯°æÇÒ ¼ö ÀÖ´Ù. Áö±Ý±îÁöÀÇ ÄÚµå º¯°æ °úÁ¤À» Á¤¸®Çϸé <¸®½ºÆ® 3>°ú °°´Ù.
<¸®½ºÆ® 3> ÃÖÀûÈ ÈÄ
int result = PlusOne(x) + PlusOne(x) * (PlusOne(x) ? PlusOne(x));
¡æ int result = PlusOne(x) + PlusOne(x) * (0);
¡æ int result = PlusOne(x) + 0;
¡æ int result = PlusOne(x);
Äڵ带 º¯°æÇÏ´Â °úÁ¤À» ÅëÇØ Çʼö Á¶°ÇÀº ÀÔ·Â °ª x¿¡ °°Àº °ªÀ» ÁÖ¸é PlusOne °á°ú °ª ¿ª½Ã Ç×»ó °°´Ù´Â °ÍÀ» ¾Ë ¼ö ÀÖ´Ù. À̸¦ ¹ÙÅÁÀ¸·Î ¡®PlusOne(x) = PlusOne(x)¡¯°¡ ¼º¸³ÇÏ°Ô µÇ¸ç, ¡®PlusOne(x) - PlusOne(x)¡¯°¡ 0À¸·Î ´ëüµÉ ¼ö ÀÖ´Ù. ÀÌ´Â ¡®(PlusOne(x) - PlusOne(x)) = 0¡¯ÀÌ ¼º¸³Çϱ⠶§¹®¿¡ °¡´ÉÇÑ °ÍÀÌ´Ù. ±× ÀÌÈÄ Äڵ带 º¯°æÇÏ´Â °úÁ¤¿¡¼µµ ¿ª½Ã ¡®(PlusOne(x) * 0) = 0¡¯°ú ¡®(PlusOne(x) + 0) = PlusOne(x)¡¯°¡ ¼º¸³ÇÑ´Ù. ÀÌ´Â ¼öÇÐÀû »ó½Ä¿¡ ±â¹ÝÀ» µÎ°í Äڵ带 ÃÖÀûÈÇÒ ¼ö ÀÖÀ½À» ÀǹÌÇÑ´Ù. Á» ´õ °£´ÜÇÑ ¿¹Á¦ <¸®½ºÆ® 4>¸¦ ÅëÇØ ´Ù¸¥ ÃÖÀûÈ ¹æ¹ýÀ» »ìÆìº¸ÀÚ.
<¸®½ºÆ® 4> ÃÖÀûÈ Àü
int result = PlusOne(x) * PlusOne(x)
<¸®½ºÆ® 4>ÀÇ ÄÚµå´Â ÇöÀç PlusOneÀ» Áߺ¹ È£ÃâÇϰí ÀÖ´Ù. PlusOneÀÌ ¡®value¿¡ °°Àº °ªÀ» ÁÖ¸é PlusOne ÇÔ¼ö´Â Ç×»ó °°Àº °á°ú¸¦ µ¹·ÁÁش١¯¸¦ ÁؼöÇϰí ÀÖ´Ù¸é PlusOne(x)¸¦ ÇÑ ¹ø¸¸ È£ÃâÇØ ±× °á°ú¸¦ ÀúÀåÇÑ ÈÄ temp º¯¼ö·Î µ¿ÀÏÇÑ °á°ú¸¦ ¾òÀ» ¼ö ÀÖ´Ù. À̹ø ¿¹Á¦´Â ÇÔ¼ö¸¦ º¯¼ö·Î ´ëÃ¼ÇØ °á°ú °ªÀ» ÀúÀåÇϰí Áߺ¹ È£Ãâ ¾øÀÌ PlusOne ÇÔ¼ö¸¦ ÇÑ ¹øÀÇ È£Ãâ·Î ÃÖÀûÈÇÑ´Ù.
<¸®½ºÆ® 5> ÃÖÀûÈ ÈÄ
int temp = PlusOne(x);
int result = temp * temp;
µÎ °¡Áö ÃÖÀûÈ ¿¹Á¦ ¸ðµÎ PlusOne(x) ÇÔ¼öÀÇ °á°ú °ªÀ» ¿¹ÃøÇÒ ¼ö ÀÖ¾ú´Ù. ÀÌ´Â CPU¿¡¼ Á¦°øÇÏ´Â ºÐ±â ¿¹Ãø°ú ´Þ¸® ¿¹Ãø ½ÇÆÐ°¡ Á¸ÀçÇÏÁö ¾Ê±â ¶§¹®¿¡ °¡´ÉÇÑ °ÍÀÌ´Ù. ÀÌ·¯ÇÑ ¼ºÁú ´öºÐ¿¡ ¨çÇÔ¼ö¸¦ °ªÀ̳ª º¯¼ö·Î ¹Ù²ãµµ Àüü ±¸¹®¿¡ Àǹ̰¡ º¯ÇÏÁö ¾ÊÀ¸¸ç, ¨è¼öÇÐÀûÀ¸·Î ÃÖÀûÈÇÒ ¼ö ÀÖ´Ù. ÀÌ¿Í °°Àº ¼ºÁúÀ» °®´Â ÇÔ¼ö¸¦ ÂüÁ¶¿¡ Åõ¸í(Referentially Transparent)ÇÑ ÇÔ¼ö¶ó°í ÇÑ´Ù. ¶ÇÇÑ ÂüÁ¶¿¡ Åõ¸íÇÑ ÇÔ¼ö´Â ÀÔ·Â °ª¿¡ µû¶ó °á°ú °ªÀÌ °áÁ¤µÇ±â ¶§¹®¿¡ °áÁ¤ ÇÔ¼ö(Deterministic Function)¶ó°í ÇÑ´Ù. ÀÌ¿¡ »ó¹ÝµÇ´Â °³³äÀº ÂüÁ¶¿¡ ºÒÅõ¸í(Referentially Opaque)ÇÑ ÇÔ¼ö ¶Ç´Â ºñ°áÁ¤ ÇÔ¼ö(Non-deterministic Function)¶ó ÇÑ´Ù. ÂüÁ¶¿¡ ºÒÅõ¸íÇÑ ÇÔ¼ö´Â µ¿ÀÏÇÑ ÀÔ·Â °ª¿¡µµ ºÒ±¸ÇÏ°í °á°ú °ªÀÌ Ç×»ó °°Áö ¾Ê´Ù.
<¸®½ºÆ® 6>¿¡ ±¸ÇöµÈ PlusOne ÇÔ¼ö´Â ÇÔ¼öÀÇ ¿ÜºÎ globalValue º¯¼ö °ªÀ» º¯°æ½ÃŲ(write) ÈÄ¿¡ ÇØ´ç º¯¼öÀÇ °ªÀ» ÂüÁ¶ÇØ °á°ú °ªÀ» ¸¸µç´Ù.
<¸®½ºÆ® 6> ÂüÁ¶¿¡ ºÒÅõ¸íÇÑ ÇÔ¼ö
int globalValue = 0;
int PlusOne(int value)
{
globalValue = globalValue + 1;
return value + globalValue;
}
±× ¶§¹®¿¡ ÀÔ·Â °ª value°¡ °°¾Æµµ °á°ú °ªÀÌ Ç×»ó °°Áö ¾Ê°Ô µÈ´Ù. ¿¹¸¦ µé¾î, PlusOne(2015)¸¦ Áߺ¹Çؼ È£ÃâÇϸé óÀ½¿¡´Â 2016, ´ÙÀ½¿¡´Â 2017À» µ¹·ÁÁÖ°Ô µÈ´Ù. ÀÌ´Â ¡®PlusOne(2015) = PlusOne(2015)¡¯°¡ ¼º¸³µÉ ¼ö ¾ø°Ô µÈ´Ù. ¶ÇÇÑ ¡®((PlusOne(2015) - PlusOne(2015)) = 0¡¯ ¿ª½Ã ¼º¸³ÇÏÁö ¾Ê´Â´Ù.
À̸¦ ÅëÇØ ¾Õ¿¡¼ »ìÆìº» ÃÖÀûÈ ¿¹Á¦ 2°³ ¸ðµÎ <¸®½ºÆ® 6>¿¡¼ ±¸ÇöÇÑ ÂüÁ¶¿¡ ºÒÅõ¸íÇÑ ÇÔ¼ö PlusOneÀ̶ó¸é ÇØ´ç »çÇ×ÀÌ ¾øÀ» °ÍÀÌ´Ù. ÂüÁ¶¿¡ ºÒÅõ¸íÇÑ ÇÔ¼ö´Â ÃÖÀûÈÇÒ ±âȸ ÀÚü°¡ ÁÙ¾îµé °ÍÀ̸ç, ¼öÇÐÀûÀ¸·Î ÇÔ¼ö¸¦ ´Ù·ç±âµµ ¾î·Æ´Ù. ¶Ç ÇÔ¼ö ¿ÜºÎ µ¥ÀÌÅ͸¦ º¯°æ½ÃŰ¹Ç·Î ÀǵµÇÏÁö ¾Ê´Â °á°ú¸¦ ¹ß»ý½Ãų ¼ö ÀÖ´Ù. ÀÌó·³ ÇÔ¼ö °á°ú °ª ¿Ü¿¡ ÇÔ¼ö ¿ÜºÎ¿¡ ÀÖ´Â »óŸ¦ º¯°æ½ÃŰ´Â °É ¡®ºÎÀÛ¿ë(Side-Effect)ÀÌ ÀÖ´Ù¡¯°í ¸»ÇÑ´Ù. ºÎÀÛ¿ëÀº ´ÙÀ½°ú °°ÀÌ ´ëÇ¥ÀûÀ¸·Î ³× °¡Áö °æ¿ì¿¡ ¹ß»ýÇÑ´Ù.
1. ÇÔ¼ö ¿ÜºÎÀÇ º¯¼ö¸¦ º¯°æ½Ãų ¶§(¿¹: Àü¿ª º¯¼ö, Á¤Àû º¯¼ö)
2. ÇÔ¼ö ÀÎÀÚ¸¦ º¯°æÇÒ ¶§(¿¹: ÂüÁ¶ º¯¼ö)
3. ȸéÀ̳ª ÆÄÀÏ¿¡ µ¥ÀÌÅ͸¦ ¾µ ¶§
4. ´Ù¸¥ ºÎÀÛ¿ëÀÌ ÀÖ´Â ÇÔ¼öÀÇ °á°ú¸¦ ÂüÁ¶ÇÒ ¶§
ÂüÁ¶¿¡ ºÒÅõ¸íÇÑ ÇÔ¼ö´Â ´ë°³ ºÎÀÛ¿ëÀÌ ÀÖ´Ù. ±×·¯³ª ºÎÀÛ¿ëÀÌ ¾ø´Ù°í ÇØ¼ ¸ðµÎ ÂüÁ¶¿¡ Åõ¸íÇÑ ÇÔ¼ö´Â ¾Æ´Ï´Ù. °¡·É ÇöÀç ½Ã°£À» µ¹·ÁÁÖ´Â ÇÔ¼ö°¡ ÀÖ´Ù°í °¡Á¤ÇØ º¸ÀÚ. ÇØ´ç ÇÔ¼ö´Â ¿ÜºÎ µ¥ÀÌÅ͸¦ ÀüÇô º¯°æ½ÃŰÁö ¾ÊÁö¸¸(ºÎÀÛ¿ëÀÌ ¾øÁö¸¸) ÇØ´ç ÇÔ¼ö¸¦ È£ÃâÇÒ ¶§¸¶´Ù ½Ã°£À̶ó´Â Àü¿ª »óÅ º¯°æÀ¸·Î ÀÎÇØ ¸Å¹ø ´Ù¸¥ °á°ú °ªÀ» µ¹·ÁÁÙ °ÍÀÌ´Ù.
C#, Java, C++¿Í °°Àº ¸í·ÉÇü ¾ð¾îµéÀº ºÎÀÛ¿ëÀ» »ç¿ëÇØ ÇÁ·Î±×·¡¹ÖÇÏ°Ô µÈ´Ù. ±×·¯³ª F#, Scala, Haskell°ú °°Àº ÇÔ¼öÇü ¾ð¾îµéÀº ºÎÀÛ¿ëÀ» ÃÖ¼ÒÈÇØ ÇÁ·Î±×·¡¹ÖÇÑ´Ù. ƯÈ÷ ÇÔ¼öÇü ¾ð¾î¿¡¼´Â ºÎÀÛ¿ëÀÌ ¾øÀ¸¸ç, ÂüÁ¶¿¡ Åõ¸íÇÑ ÇÔ¼ö¸¦ ¡®¼ø¼ö ÇÔ¼ö(Pure Function)¡¯¶ó°í ÇÑ´Ù. ¼ø¼ö ÇÔ¼ö´Â ÂüÁ¶¿¡ Åõ¸íÇϹǷΠ¿¹ÃøÀÌ °¡´ÉÇÏ´Ù. ±× ´öºÐ¿¡ ÇÔ¼ö¸¦ °ªÀ̳ª º¯¼ö·Î ´ëüÇÒ ¼ö ÀÖ¾î ¸í·ÉÇü ÇÁ·Î±×·¡¹Öº¸´Ù ´õ ¸¹Àº ÃÖÀûÈ ±âȸ¸¦ ¾òÀ» ¼ö ÀÖ´Ù. ¶Ç ÇÔ¼ö¸¦ ¼öÇÐÀûÀ¸·Î ´Ù·ê ¼ö ÀÖ¾î Á¤È®¼º Áõ¸íÀÌ ½¬¿öÁüÀ¸·Î Å×½ºÆ®¿Í µð¹ö±ë¿¡µµ ¿ëÀÌÇÏ´Ù.
ºÎÀÛ¿ëÀÌ ¾øÀ¸¹Ç·Î ÇÔ¼ö ³»ºÎ ±¸Çö¿¡¼ ÇÊ¿äÇÑ Áö¿ª º¯¼ö¿Í °á°ú °ª ¿Ü¿¡´Â ¿ÜºÎ¿¡ ¿µÇâÀ» ÁÖÁö ¾Ê´Â´Ù. ÀÌ´Â ÇÔ¼ö°¡ ¿øÀÚÀû(Atomic) ¼ºÁúÀ» °®°Ô µÅ ƯÁ¤ ±â´ÉÀ» ÇÔ¼ö ´ÜÀ§·Î ¿Ï·áÇϵµ·Ï ¼³°è¸¦ °¿äÇÑ´Ù. ÀÌ´Â ÄÚµåÀÇ °¡µ¶¼º°ú À¯Áö °ü¸® ÆíÀǼºÀ» Çâ»óÇÏ°Ô µÈ´Ù. °´Ã¼ÁöÇâ ¼³°è ¿øÄ¢¿¡¼ ¹Ù¶óº¸¸é ÇÔ¼ö ´ÜÀ§·Î ´ÜÀÏ Ã¥ÀÓ ¿øÄ¢(SRP, Single Responsibility Principle)À» ÁؼöÇÏ°Ô µÈ´Ù. ÇÔ¼öÇü ¾ð¾î´Â ÀÌ·¯ÇÑ ¼ºÁúÀ» °®´Â ÇÔ¼ö ±¸ÇöÀ» ¾ð¾î Â÷¿ø¿¡¼ Áö¿øÇÏ°í °¿äÇÑ´Ù.
ÀÌ ¸ðµç Ư¡Àº ¿¹Ãø °¡´ÉÇÑ ÇÔ¼ö·ÎºÎÅÍ ½ÃÀ۵ƴÙ. ¿¹Ãø °¡´ÉÇÑ ÇÔ¼ö¸¦ ¸¸µé±â À§Çؼ´Â ºÎÀÛ¿ëÀÌ Á¸ÀçÇØ¼´Â ¾È µÈ´Ù. ºÎÀÛ¿ëÀº °á±¹ ¿ÜºÎ¿¡ ¿µÇâÀ» ÁÖÁö ¾Ê´Â °ÍÀÌ´Ù. À̸¦ Á» ´õ ±¸Ã¼ÀûÀ¸·Î ÄÚµå ¼öÁØÀ¸·Î ÇØ¼®Çϸé, ÇÑ ¹ø ÃʱâÈµÈ µ¥ÀÌÅÍ´Â º¯°æ½ÃŰÁö ¾Ê´Â °ÍÀÌ´Ù. ÀÌ·¯ÇÑ Æ¯Â¡¿¡ ±âÀÎÇØ ÇÔ¼öÇü ¾ð¾î´Â º¯°æ ºÒ°¡´É¼º(Immutability)À̶ó´Â ÇÁ·Î±×·¡¹Ö ¸ðµ¨¿¡ »Ñ¸®¸¦ µÎ°í ÀÖ´Ù. ÀÌ·ÐÀûÀ¸·Î´Â ¶÷´Ù ´ë¼ö¿¡ ±Ù°£À» µÎ°í ÀÖ´Ù.
2005³â ÀÌÈÄ ¸ÖƼ ÄÚ¾î·Î CPU°¡ ¹ßÀüÇÏ¸é¼ º´·Ä ÇÁ·Î±×·¡¹ÖÀº Çʼö »çÇ×ÀÌ µÇ°í ÀÖ´Ù. ±×·¯³ª ´Ù¾çÇÑ º´·Ä ¶óÀ̺귯¸®¸¦ »ç¿ëÇÏ´Â °Í¸¸À¸·Î ¼º´É Çâ»óÀ» ±â´ëÇϱⰡ ½±Áö ¾Ê´Ù. ±× ÀÌÀ¯´Â º´·Ä ¶óÀ̺귯¸®ÀÇ ¹®Á¦¶ó±âº¸´Ù´Â ¸í·ÉÇü ¾ð¾î°¡ ÁöÇâÇϰí ÀÖ´Â µ¥ÀÌÅÍ º¯°æ ÇÁ·Î±×·¡¹Ö ¸ðµ¨¿¡ ÀÖ´Ù. µ¥ÀÌÅÍ º¯°æÀ¸·Î ÀÎÇÑ ´ëÇ¥ÀûÀÎ ¹®Á¦ Áß Çϳª´Â µ¥ÀÌÅÍ ·¹À̽º(Data Race)´Ù.
<¸®½ºÆ® 7> µ¥ÀÌÅÍ ·¹À̽º
using System;
using System.Threading;
namespace DataRace
{
class Program
{
static int count = 0;
static void Main()
{
Thread workThread1 = new Thread(WorkThreadJob1);
Thread workThread2 = new Thread(WorkThreadJob2);
workThread1.Start();
workThread2.Start();
workThread1.Join();
workThread2.Join();
Console.WriteLine ("Final count: {0}", count);
}
static void WorkThreadJob1()
{
for (int i = 0; i < 5; i++)
{
count++;
}
}
static void WorkThreadJob2()
{
for (int i = 0; i < 5; i++)
{
count++;
}
}
}
}
<¸®½ºÆ® 7>ÀÇ Äڵ带 ÄÄÆÄÀÏÇØ ½ÇÇàÇÏ¸é °á°ú °ªÀÌ Ç×»ó °°Áö ¾Ê´Ù. WorkThreadJob1 ÇÔ¼ö¿Í WorkThreadJob2 ÇÔ¼ö¿¡ ºÎÀÛ¿ëÀÌ Àֱ⠶§¹®ÀÌ´Ù. ±×·¯¹Ç·Î ÂüÁ¶¿¡ Åõ¸íÇÏÁöµµ ¾Ê´Ù. <¸®½ºÆ® 7>ÀÇ µ¥ÀÌÅÍ ·¹À̽º ¹ß»ý °úÁ¤À» Á» ´õ ÀÚ¼¼È÷ È®ÀÎÇϱâ À§ÇØ Sleep ÇÔ¼ö¿Í ȸé Ãâ·Â ÇÔ¼ö¸¦ Ãß°¡ÇÑ ÈÄ µ¥ÀÌÅÍ ·¹À̽º ¹ß»ý °úÁ¤À» »ìÆìº¸ÀÚ(<¸®½ºÆ® 8> ÂüÁ¶).
<¸®½ºÆ® 8> µ¥ÀÌÅÍ ·¹À̽º ¹ß»ý °úÁ¤ È®ÀÎÇϱâ
using System;
using System.Threading;
namespace DataRace_in_Detail
{
class Program
{
static int count = 0;
static void Main()
{
Console.WriteLine("Work Thread1 Work Thread2");
Console.WriteLine("=========================================================");
Thread workThread1 = new Thread(WorkThreadJob1);
Thread workThread2 = new Thread(WorkThreadJob2);
workThread1.Start();
workThread2.Start();
workThread1.Join();
workThread2.Join();
Console.WriteLine("=========================================================");
Console.WriteLine("Final count: {0}
", count);
}
static void WorkThreadJob1()
{
for (int i = 0; i < 5; i++)
{
int tmp = count;
Console.WriteLine("Read count={0}", tmp);
Thread.Sleep(50);
tmp++;
Console.WriteLine("Incremented tmp to {0}", tmp);
Thread.Sleep(20);
count = tmp;
Console.WriteLine("Written count={0}", tmp);
Thread.Sleep(30);
}
}
static void WorkThreadJob2()
{
for (int i = 0; i < 5; i++)
{
int tmp = count;
Console.WriteLine(" Read count={0}", tmp);
Thread.Sleep(20);
tmp++;
Console.WriteLine(" Incremented tmp to {0}", tmp);
Thread.Sleep(10);
count = tmp;
Console.WriteLine(" Written count={0}", tmp);
Thread.Sleep(40);
}
}
}
}
<¸®½ºÆ® 8>ÀÇ Äڵ带 ÄÄÆÄÀÏÇØ ½ÇÇàÇϸé <±×¸² 1>°ú °°ÀÌ µ¥ÀÌÅÍ ·¹À̽º ¹ß»ý °úÁ¤À» È®ÀÎÇÒ ¼ö ÀÖ´Ù. ¡®Work Thread1¡¯¿¡¼ count °ªÀ» ÀÐÀº ÈÄ¿¡ ¡®Work Thread2¡¯¿¡¼µµ count °ªÀ» ÀÐ°í ¿¬»ê(count++) ÈÄ count °ªÀ» º¯°æ½ÃŲ´Ù. ±×·¯³ª ¡®Work Thread1¡¯¿¡¼´Â ¡®Work Thread2¡¯¿¡¼ º¯°æµÈ count °ªÀ» È®ÀÎÇÏÁö ¸øÇϰí ÀÌÀü °ªÀ¸·Î ¿¬»êÇØ count °ªÀ» º¯°æ½Ã۱⠶§¹®¿¡ ¿Ã¹Ù¸¥ count °ªÀ» ¾òÁö ¸øÇÑ´Ù. ±× °á°ú ¡®6¡¯À̶ó´Â À߸øµÈ °á°ú µ¥ÀÌÅ͸¦ ¾ò°Ô µÈ´Ù.
ÀÌ·¯ÇÑ µ¥ÀÌÅÍ ·¹À̽º ¹®Á¦´Â µ¿±âȸ¦ ÅëÇØ ÇØ°áÇÒ ¼ö ÀÖ´Ù. µ¿±âȸ¦ ±¸ÇöÇÏ´Â ¹æ¹ýÀº ¸Å¿ì ´Ù¾çÇÏ´Ù. <¸®½ºÆ® 9>´Â C#¿¡¼ Á¦°øÇÏ´Â lock Ű¿öµå¸¦ »ç¿ëÇØ µ¥ÀÌÅÍ ·¹À̽º¸¦ ÇØ°áÇÑ´Ù. lockÀº C#¿¡¼ Á¦°øÇϴ Ű¿öµå °¡¿îµ¥ °¡Àå ½±°Ô µ¿±âȸ¦ ±¸ÇöÇÏ´Â ¹æ¹ýÀÌ´Ù. lock Ű¿öµå ºí·ÏÀº ÀÓ°è ¿µ¿ª(Critical Section)À¸·Î 󸮵Ǹç, ƯÁ¤ ½º·¹µå°¡ ÀÓ°è ¿µ¿ª¿¡ ÀÖ´Â µ¿¾È ´Ù¸¥ ½º·¹µå´Â lock ºí·ÏÀÌ ÇØÁ¦µÉ ¶§±îÁö ´ë±âÇÑ´Ù. lock ºí·ÏÀÌ ÇØÁ¦µÇ¸é ´Ù¸¥ ½º·¹µå°¡ ÀÓ°è ¿µ¿ª¿¡ µé¾î°¥ ¼ö ÀÖ°Ô µÈ´Ù. À̸¦ ÅëÇØ µ¥ÀÌÅÍ º¯°æ°ú °ü·ÃµÈ ÀÛ¾÷À» »óÈ£ ¹èŸÀû(Mutual-Exclusion)À¸·Î ¼öÇàÇÒ ¼ö ÀÖ´Ù.
<¸®½ºÆ® 9> µ¿±âȸ¦ ÅëÇÑ µ¥ÀÌÅÍ ·¹À̽º Á¦°ÅÇϱâ
using System;
using System.Threading;
namespace DataRace_Solution_byLock
{
public class Test
{
static int count = 0;
static readonly object countLock = new object();
static void Main()
{
Console.WriteLine("Work Thread1 Work Thread2");
Console.WriteLine("=========================================================");
Thread workThread1 = new Thread(WorkThreadJob1);
Thread workThread2 = new Thread(WorkThreadJob2);
workThread1.Start();
workThread2.Start();
workThread1.Join();
workThread2.Join();
Console.WriteLine("=========================================================");
Console.WriteLine("Final count: {0}
", count);
Console.WriteLine("Final count: {0}", count);
}
static void WorkThreadJob1()
{
for (int i = 0; i < 5; i++)
{
lock (countLock)
{
int tmp = count;
Console.WriteLine("Read count={0}", tmp);
Thread.Sleep(50);
tmp++;
Console.WriteLine("Incremented tmp to {0}", tmp);
Thread.Sleep(20);
count = tmp;
Console.WriteLine("Written count={0}", tmp);
}
Thread.Sleep(30);
}
}
static void WorkThreadJob2()
{
for (int i = 0; i < 5; i++)
{
lock (countLock)
{
int tmp = count;
Console.WriteLine(" Read count={0}", tmp);
Thread.Sleep(20);
tmp++;
Console.WriteLine(" Incremented tmp to {0}", tmp);
Thread.Sleep(10);
count = tmp;
Console.WriteLine(" Written count={0}", tmp);
}
Thread.Sleep(40);
}
}
}
}
<¸®½ºÆ® 9>ÀÇ ½ÇÇà °á°ú´Â <±×¸² 2>¿Í °°ÀÌ µ¥ÀÌÅÍ ·¹À̽º°¡ Á¦°ÅµÅ Ç×»ó °°Àº °á°ú °ªÀ» ¾ò°Ô µÈ´Ù. WorkThreadJob1°ú WorkThreadJob2 ÇÔ¼ö´Â ºÎÀÛ¿ëÀÌ ±Ùº»ÀûÀ¸·Î Á¸ÀçÇÏÁö¸¸, À̸¦ µ¿±âÈ·Î Á¦°ÅÇϰí ÀÖ´Ù.
ºÎÀÛ¿ëÀº µ¿±âȸ¦ ÅëÇØ Á¦°ÅÇÒ ¼ö ÀÖÁö¸¸, ÀÌ·¯ÇÑ µ¥ÀÌÅÍ ·¹À̽º ¹®Á¦´Â ¹ß°ßÇϱ⵵ ÀçÇöÇϱ⵵ ½±Áö ¾Ê´Ù.
´õ¿íÀÌ µ¿±âÈ·Î ÀÎÇØ ¼º´É Çâ»ó¿¡ Å« Àå¾Ö¸¦ ÃÊ·¡ÇÏ´Â °æ¿ìµµ ¸¹´Ù. ±×·¡¼ ´ëºÎºÐ º´·Ä ¶óÀ̺귯¸®µéÀº ¼º´É Àå¾Ö¸¦ ÃÖ¼ÒÈ´Â ¾ÆÁÖ °¡º¿î µ¿±âÈ ±â´ÉÀ» Á¦°øÇÑ´Ù. ¶Ç µ¿±âÈ·Î ÀÎÇØ µ¥µå¶ô(Deadlock)À̶ó´Â »õ·Î¿î ¹®Á¦°¡ ¹ß»ýÇÒ ¼ö ÀÖ´Ù. µ¥µå¶ôÀº ¡®2°³ ÀÌ»óÀÇ ÀÛ¾÷ÀÌ »ó´ë¹æÀÇ ÀÛ¾÷ÀÌ ³¡³ª±â¸¸À» ±â´Ù¸®´Ù°¡ °á°úÀûÀ¸·Î ¾Æ¹«°Íµµ ¿Ï·áÇÏÁö ¸øÇÏ´Â »óÅ¡¯¸¦ ÀǹÌÇÑ´Ù. <¸®½ºÆ® 9>¿¡¼ ºÎÀÛ¿ëÀ» ÇØ°áÇϱâ À§ÇØ »ç¿ëÇÑ µ¿±âÈ lock Ű¿öµå·Î µ¥µå¶ôÀÌ ¹ß»ýÇÏ´Â ¿¹¸¦ »ìÆìº¸ÀÚ(<¸®½ºÆ® 10> ÂüÁ¶).
<¸®½ºÆ® 10> µ¥µå¶ô
using System;
using System.Threading;
namespace Deadlock
{
class Program
{
private static object objLockA = new Object();
private static object objLockB = new Object();
public static void Main()
{
Thread workThread1 = new Thread(WorkThreadJob1);
Thread workThread2 = new Thread(WorkThreadJob2);
workThread1.Start();
workThread2.Start();
workThread1.Join();
workThread2.Join();
Console.WriteLine("Done Processing...");
}
private static void WorkThreadJob1()
{
lock (objLockA)
{
Console.WriteLine("Trying to acquire lock on ObjLockB");
Thread.Sleep(1000);
lock (objLockB)
{
// µ¥ÀÌÅÍ º¯°æ ¿µ¿ª, ±×·¯³ª Àý´ë È£ÃâµÇÁö ¾Ê´Â´Ù.
Console.WriteLine("In WorkThreadJob1 Critical Section.");
}
}
}
private static void WorkThreadJob2()
{
lock (objLockB)
{
Console.WriteLine("Trying to acquire lock on ObjLockA");
lock (objLockA)
{
// µ¥ÀÌÅÍ º¯°æ ¿µ¿ª, ±×·¯³ª Àý´ë È£ÃâµÇÁö ¾Ê´Â´Ù.
Console.WriteLine("In WorkThreadJob2 Critical Section.");
}
}
}
}
}
<¸®½ºÆ® 10>À» ½ÇÇàÇϸé <±×¸² 3>°ú °°ÀÌ WorkThreadJob1°ú WorkThreadJob2 ¸ðµÎ ÀÓ°è ¿µ¿ª¿¡ ÇØ´çÇÏ´Â ÄÚµå ºí·ÏÀ» Àý´ë È£ÃâÇÏÁö ¾Ê´Â´Ù. ¼·Î ÀÓ°è ¿µ¿ªÀÌ ³¡³ª±â¸¸À» ±â´Ù¸®°í ÀÖ¾î °á°úÀûÀ¸·Î ÇÁ·Î±×·¥Àº ´õ´Â ÁøÇàÇÏÁö ¾Ê°Ô µÈ´Ù. µ¥µå¶ôÀº µ¿±âȸ¦ À§ÇØ ÀÓ°è ¿µ¿ªÀ» µé¾î°¡±â À§ÇÑ ¹«ÇÑ ±â´Ù¸²À¸·Î ¹ß»ýÇÑ´Ù. µ¥µå¶ôÀ» ÇØ°áÇϱâ À§Çؼ´Â ¾î´À ÇÑÂÊ ½º·¹µå¿¡¼ ±â´Ù¸²À» Æ÷±âÇØ¾ß ÇÑ´Ù. ±Ùº»ÀûÀÎ ÇØ°áÃ¥Àº ´ç¿¬È÷ µ¥µå¶ôÀÌ ¹ß»ýÇÏÁö ¾Êµµ·Ï ÇÏ´Â °ÍÀÌ´Ù. ´ëÇ¥ÀûÀ¸·Î ŸÀ̸Ӹ¦ ÀÌ¿ëÇÏ´Â ¹æ¹ýÀÌ ÀÖ´Ù. ÀÓ°è ¿µ¿ª¿¡ µé¾î°¡±â À§ÇÑ ´ë±â ½Ã°£À» ¼³Á¤ÇÔÀ¸·Î½á ÁöÁ¤ÇÑ ½Ã°£ÀÌ ÃʰúÇÏ¸é ±â´Ù¸²À» Æ÷±âÇϵµ·Ï ÇÏ´Â °ÍÀÌ´Ù.
<¸®½ºÆ® 11>Àº Monitor Ŭ·¡½º¿¡¼ Á¦°øÇÏ´Â ¡®public static bool TryEnter(object obj, int millisecondsTimeout);¡¯ Á¤Àû ¸â¹ö ÇÔ¼ö¸¦ »ç¿ëÇß´Ù. 5Ãʸ¦ ±â´Ù¸®°í ±× ¾È¿¡ ÀÓ°è ¿µ¿ª¿¡ µé¾î°¥ ¼ö ¾ø´Ù°í ÆÇ´ÜµÇ¸é ÀÓ°è ¿µ¿ª ÁøÀÔÀ» Æ÷±âÇÒ °ÍÀÌ´Ù.
<¸®½ºÆ® 11> ŸÀ̸Ӹ¦ ÅëÇÑ µ¥µå¶ô Á¦°Å
using System;
using System.Threading;
namespace Deaklock_Solution_byTime
{
class Program
{
private static object objLockA = new Object();
private static object objLockB = new Object();
public static void Main()
{
Thread workThread1 = new Thread(WorkThreadJob1);
Thread workThread2 = new Thread(WorkThreadJob2);
workThread1.Start();
workThread2.Start();
workThread1.Join();
workThread2.Join();
Console.WriteLine("Done Processing...");
}
private static void WorkThreadJob1()
{
lock (objLockA)
{
Console.WriteLine("Trying to acquire lock on objLockB");
Thread.Sleep(1000);
if (Monitor.TryEnter(objLockB, 5000))
{
try
{
Console.WriteLine("In WorkThreadJob1 Critical Section.");
}
finally
{
Monitor.Exit(objLockB);
}
}
else
{
Console.WriteLine("Unable to acquire lock, exiting WorkThreadJob1.");
}
}
}
private static void WorkThreadJob2()
{
lock (objLockB)
{
Console.WriteLine("Trying to acquire lock on objLockA");
lock (objLockA)
{
Console.WriteLine("In WorkThreadJob2 Critical Section.");
}
}
}
}
}
Monitor Ŭ·¡½º¿¡ Á¦°øÇÏ´Â TryEnter ÇÔ¼ö¸¦ ÅëÇØ <±×¸² 4>¿Í °°ÀÌ 5ÃÊ ÀÌÈÄ¿¡´Â WorkThreadJob2 ÇÔ¼ö°¡ ¼öÇàµÇ´Â °ÍÀ» È®ÀÎÇÒ ¼ö ÀÖ´Ù.

µ¥ÀÌÅÍ ·¹À̽º´Â µ¥ÀÌÅÍ º¯°æ ¶§¹®¿¡ ¹ß»ýÇÏ´Â ¹®Á¦À̸ç, À̸¦ ÇØ°áÇϰíÀÚ µ¿±âȸ¦ µµÀÔÇß´Ù. ±×·¯³ª µ¿±âÈ´Â µ¥µå¶ôÀ̶ó´Â »õ·Î¿î ¹®Á¦¸¦ À¯¹ßÇÒ ¼ö ÀÖ´Ù. ¹®Á¦ ÇØ°á ¹æ¹ýÀÌ »õ·Î¿î ¹®Á¦¸¦ ³º´Â ¿ôÁö ¸øÇÒ »óȲÀÌ ¹ß»ýÇÑ °ÍÀÌ´Ù. ÀÌ·¯ÇÑ ¹®Á¦µéÀº ¸ðµÎ µ¥ÀÌÅÍ º¯°æÀ¸·Î ÀÎÇØ ¹ß»ýÇÑ´Ù. ¸ÖƼ ÄÚ¾î¿Í ¸Å´Ï ÄÚ¾î·Î ¹ßÀüÇÏ´Â °úÁ¤¿¡¼ µ¥ÀÌÅÍ º¯°æÀ¸·Î ·ÎÁ÷À» ÀÛ¼ºÇÏ°Ô µÇ¸é ÀÌ·¯ÇÑ ¹®Á¦µéÀÌ ´õ¿í ºó¹øÇÏ°Ô »ý°Ü³¯ °ÍÀÌ´Ù. À̸¦ ÇØ°áÇϱâ À§ÇÑ ³ë·Â°ú ½Ã°£ ¿ª½Ã ÇÊ¿äÇÏ´Ù´Â ¾ê±â´Ù. ±×·¸´Ù¸é ÀÌ·¯ÇÑ ¹®Á¦¸¦ ±Ùº»ÀûÀ¸·Î ÇØ°áÇÒ ¼ö ¾øÀ»±î? µ¥ÀÌÅÍ ·¹À̽º¿Í µ¥µå¶ô °°Àº ¹®Á¦°¡ Á¸ÀçÇÒ ¼ö ¾øµµ·Ï ÇÒ ¼ö´Â ¾øÀ»±î? µ¿±âȰ¡ ¾ø´Â ÇÁ·Î±×·¡¹Ö ¸ðµ¨Àº ¾øÀ»±î?
ÀÌ·¯ÇÑ ¹®Á¦ÀÇ ±Ùº»ÀûÀÎ ¿øÀÎÀº µ¥ÀÌÅÍ º¯°æÀ¸·ÎºÎÅÍ ¹ß»ýÇÏ´Â ºÎÀÛ¿ëÀÌ´Ù. ÇÔ¼öÇü ¾ð¾î´Â ±âº»ÀûÀ¸·Î µ¥ÀÌÅÍ º¯°æÀ» Á¦°øÇÏÁö ¾Ê±â ¶§¹®¿¡ µ¥ÀÌÅÍ ·¹À̽º ¹®Á¦ ÀÚü°¡ ¹ß»ýÇÏÁö ¾Ê´Â´Ù. µ¿±âÈ ¿ª½Ã ÇÔ¼öÇü ¾ð¾î¿¡¼´Â ÁÖ¿ä °ü½É»ç°¡ µÉ ¼ö ¾ø´Ù. µ¿±âȰ¡ Á¦°ÅµÇ±â ¶§¹®¿¡ ÀÚ¿¬½º·´°Ô µ¥µå¶ô ¶ÇÇÑ ÇØ°áµÈ´Ù. ÇÔ¼öÇü ¾ð¾î°¡ ÃÖ±Ù µé¾î ÁÖ¸ñ¹Þ°í ÀÖ´Â ÀÌÀ¯ Áß Çϳª´Ù.
ÇÔ¼öÇü ¾ð¾î¿¡¼´Â µ¥ÀÌÅÍ º¯°æÀ¸·Î ¹ß»ýÇÏ´Â ¹®Á¦µéÀ» °í¹ÎÇÒ Çʿ䰡 ¾ø´Ù. ±×·¯³ª ÀÌ·¯ÇÑ ÇÁ·Î±×·¡¹Ö ¸ðµ¨ÀÌ ÀåÁ¡¸¸ ÀÖ´Â °Ç ¾Æ´Ï´Ù. µ¥ÀÌÅÍ º¯°æ ºÒ°¡´É¼ºÀ¸·Î ÀÎÇØ ÃÊ·¡ÇÏ´Â ¾Ö·Î »çÇ× ¿ª½Ã Á¸ÀçÇÑ´Ù. ±×·¯³ª µ¥ÀÌÅÍ º¯°æ ºÒ°¡´É¼ºÀ¸·Î ÀÎÇØ ÇÔ¼öÀÇ ÀÎÀÚ °ªÀÌ º¯ÇÏÁö ¾Ê´Â´Ù¸é ÇÔ¼ö´Â Ç×»ó °°Àº °á°ú¸¦ µ¹·ÁÁÖ°í(ÂüÁ¶ Åõ¸í¼º), °á°ú °ª ¿Ü¿¡´Â ÇÔ¼ö ¿ÜºÎ¿¡ ¿µÇâÀ» ¹ÌÄ¡Áö ¾Ê±â ¶§¹®¿¡ ÀǵµÇÏÁö ¾Ê´Â °á°ú¸¦ ¹ß»ý½ÃŰÁö ¾ÊÀ¸¹Ç·Î(ºÎÀÛ¿ëÀÌ ¾ø´Ù) °á°ú¸¦ ¿¹ÃøÇÒ ¼ö ÀÖ´Â ÇÔ¼ö(¼ø¼ö ÇÔ¼ö)°¡ µÈ´Ù. ÀÌ·¯ÇÑ ¿¹Ãø °¡´ÉÇÑ ÇÔ¼ö´Â ¼öÇÐÀûÀ¸·Î ´Ù¸¦ ¼ö ÀÖ¾î Á» ´õ ¸¹Àº ÃÖÀûÈ ±âȸ¿Í Á¤È®¼ºÀ» ¾ò´Â´Ù.
Ãâó : ¸¶ÀÌÅ©·Î¼ÒÇÁÆ®¿þ¾î 9¿ùÈ£
Á¦°ø : µ¥ÀÌÅÍ Àü¹®°¡ Áö½ÄÆ÷ÅÐ DBguide.net