- °³¿ä
- ¸ñ·Ï
- Lock-free Stack
- Lock-free Queue
- ¸µÅ©
1 °³¿ä
¶ôÀ» »ç¿ëÇÏÁö ¾Ê´Â ´ÙÁß ½º·¹µå¿ë ¾Ë°í¸®Áò/ÀڷᱸÁ¶. ¶ô ¶§¹®¿¡ ¼º´ÉÀÌ ½É°¢ÇÒ Á¤µµ·Î ¶³¾îÁ® º» ÀûÀº ¾ø´Ù¸¸, Lock Free~ ¿ØÁö ±âºÐ ÁÁÀº ´Ü¾î°¡ ¾Æ´Ñ°¡.
ÀϹÝÀûÀ¸·Î CPU ·¹º§¿¡¼ Á¦°øÇÏ´Â ¾ÆÅä¹Í ¿¬»êÀ» °¡Áö°í ±¸ÇöÇÑ´Ù. ±×·¸±â ¶§¹®¿¡ ¿¬»ê Áö¿ø ¿©ºÎ¶ó´øÁö, ¸Þ¸ð¸® Á¤·Ä ¹®Á¦¶ó´øÁö ²Ï ½Å°æ½áÁà¾ß ÇÑ´Ù. À©µµ¿ìÁî¿¡¼ Á¦°øÇÏ´Â ¾ÆÅä¹Í ¿¬»êÀº
¿©±â¿¡ °¡¸é ³ª¿ÍÀÖ´Ù. ¾î¼Àºí¸®¸¦ Á» ´õ ¾È´Ù¸é ¹º°¡ »õ·Î¿î ¼¼°è°¡ ¿¸± °Íµµ °°Àºµ¥...
2008-01-08
´ë·« 1³â µ¿¾È ÀÌ·¡Àú·¡ »ç¿ëÇØº» °á°ú, ¾ÆÁ÷Àº ½Ã±â»óÁ¶¶ó´Â °á·Ð¿¡ µµ´ÞÇß´Ù. ÀÏ´Ü Äڵ尡 ¾î¶»°Ô µ¹¾Æ°¡´ÂÁö ÀÌÇØÇϱⰡ ¾î·Á¿î µ¥´Ù°¡ ¹ö±×°¡ ¹ß»ýÇØµµ ÀçÇöÀÌ ¸Å¿ì ¾î·Æ´Ù. °£´ÜÇÑ ½ºÇɶô Á¤µµ¾ß º° ¹®Á¦°¡ ¾ø´Ù¸¸... ¸Ó¸® ÁÁÀº ºÐµéÀÌ ¾ÈÁ¤ÀûÀÎ ÄÚµå Â¥ÁÙ ¶§±îÁö ±â´Ù¸®ÀÚ.
2 ¸ñ·Ï
ÀÏ´ÜÀº À©µµ¿ìÁî Àü¿ëÀÌ´Ù. *nix °è¿¿¡ InterlockedXXX ÇÔ¼ö ½Ã¸®Áî°¡ ÀÖ´ÂÁö´Â ¸ð¸£°Ú´Ù. ÀÖ°ÚÁö. ÀÖ´Ù¸é ÇÔ¼ö¸¸ ¹Ù²ãÁÜÀ¸·Î¼ º° ¹«¸® ¾øÀÌ ÄÄÆÄÀÏ µÉ ¼öµµ? ¾Æ ¸ô¶ó. ³ªÁß¿¡ °¥ ÀÏ »ý±â°Åµç »ý°¢ÇÏÀÚ.
±×·±µ¥ °¡¸¸È÷ »ý°¢ÇØ º¸¸é, ½ºÅÃÀ̵ç Å¥µç µé¾î°¡´Â ¾ÆÀÌÅÛÀÌ °¹¼ö°¡ Á¤ÇØÁ® ÀÖÁö ¾Ê´Ù¸é, ¸Þ¸ð¸®¸¦ µ¿ÀûÀ¸·Î ÇÒ´çÇØ¼ ³ëµå¸¦ Ãß°¡ÇØ¾ß ÇÑ´Ù. ±×·¸´Ù¸é ¸Þ¸ð¸® ÇÒ´ç ¾È¿¡¼ ÀϾ´Â Á÷·ÄÈ´Â ¾î¶»°Ô ÇÒ °ÍÀΰ¡? ÀÌ ¾È¿¡¼ ¶ô ¾²¸é ¸»Â¯ µµ·ç¹¬ ¾Æ´Ñ°¡? Ç®(pool) ¹æ½ÄÀÇ ÇÒ´çÀÚ¸¦ ¸¸µç ´ÙÀ½, ±× ¾È¿¡¼ ½ºÇɶôÀ» ÀÌ¿ëÇØ Á÷·Äȸ¦ ÇÏ¸é ºÎ´ãÀº ÁÙ°ÚÀ¸³ª, ¹º°¡ ±Ùº»ÀûÀÎ ÇØ°áÃ¥ÀÌ ¾Æ´Ï´Ù. ±Ùº»ÀûÀÎ ÇØ°áÀ» À§Çؼ´Â (Ä¿³Î ·¹º§ÀÇ) ¶ôÀ» »ç¿ëÇÏÁö ¾Ê´Â ¸Þ¸ð¸® ÇÒ´çÀÚ°¡ ÇÊ¿äÇÏ´Ù!
2.1 Lock-free Stack
XP À̻󿡼´Â SList ÇÔ¼ö±ºÀ» ÀÌ¿ëÇØ¼ °£´ÜÇÏ°Ô ¸¸µé ¼ö ÀÖ´Ù.
////////////////////////////////////////////////////////////////////////////////
/// \file LockFreeStack.h
/// \author excel96
/// \date 2006.9.29
////////////////////////////////////////////////////////////////////////////////
#pragma once
////////////////////////////////////////////////////////////////////////////////
/// \class cLockFreeStack
/// \brief ¶ôÀ» µû·Î »ç¿ëÇÏÁö ¾Ê´Â ½ºÅÃ. XP À̻󿡼¸¸ »ç¿ë °¡´ÉÇÏ´Ù.
////////////////////////////////////////////////////////////////////////////////
template
<
typename T,
template <typename> class AL = std::allocator
>
class cLockFreeStack
{
private:
#pragma pack(push)
#pragma pack(MEMORY_ALLOCATION_ALIGNMENT)
/// À¯Àú µ¥ÀÌÅ͸¦ ÀúÀåÇϱâ À§ÇÑ ±¸Á¶Ã¼.
struct NODE
{
SLIST_ENTRY List;
T Data;
};
#pragma pack(pop)
SLIST_HEADER m_ListHead; ///< ¸®½ºÆ® Çìµå.
AL<NODE> m_Allocator; ///< ¸Þ¸ð¸® ÇÒ´çÀÚ.
public:
/// \brief »ý¼ºÀÚ.
cLockFreeStack()
{
InitializeSListHead(&m_ListHead);
}
/// \brief ¼Ò¸êÀÚ.
~cLockFreeStack()
{
Clear();
}
public:
/// \brief µ¥ÀÌÅ͸¦ Ãß°¡ÇÑ´Ù.
/// \param data Ãß°¡ÇÒ µ¥ÀÌÅÍ.
void Push(const T& data)
{
NODE* newNode = m_Allocator.allocate(1);
m_Allocator.construct(newNode, NODE());
newNode->Data = data;
InterlockedPushEntrySList(&m_ListHead, &newNode->List);
}
/// \brief µ¥ÀÌÅ͸¦ »Ì¾Æ³½´Ù.
/// \param data »Ì¾Æ³½ µ¥ÀÌÅ͸¦ ¾µ º¯¼ö.
/// \return bool µ¥ÀÌÅ͸¦ »Ì¾Æ³½ °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇϰí,
/// µ¥ÀÌÅͰ¡ ¾ø´Â °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
bool Pop(T& data)
{
PSLIST_ENTRY entry = InterlockedPopEntrySList(&m_ListHead);
if (entry)
{
NODE* node = reinterpret_cast<NODE*>(entry);
data = node->Data;
m_Allocator.destroy(node);
m_Allocator.deallocate(node, 0);
return true;
}
return false;
}
/// \brief ¸ðµç µ¥ÀÌÅ͸¦ »èÁ¦ÇÑ´Ù.
void Clear()
{
T data;
while (Pop(data))
;
}
private:
/// \brief º¹»ç »ý¼º ±ÝÁö.
cLockFreeStack(const cLockFreeStack&) {}
/// \brief ´ëÀÔ ±ÝÁö.
cLockFreeStack& operator = (const cLockFreeStack&) { return *this; }
};
2.2 Lock-free Queue
Å¥ °°Àº °æ¿ì¿¡´Â »ðÀÔ/»èÁ¦°¡ ÀϾ´Â °÷ÀÌ ¼·Î ´Ù¸£¹Ç·Î ¾à°£ º¹ÀâÇÏ´Ù.
////////////////////////////////////////////////////////////////////////////////
/// \file LockFreeQueue.h
/// \author excel96
/// \date 2006.9.29
////////////////////////////////////////////////////////////////////////////////
#pragma once
////////////////////////////////////////////////////////////////////////////////
/// \class cLockFreeQueue
/// \brief ¶ôÀ» µû·Î »ç¿ëÇÏÁö ¾Ê´Â Å¥. 98 À̻󿡼´Â »ç¿ë °¡´ÉÇÏ´Ù.
////////////////////////////////////////////////////////////////////////////////
template
<
typename T,
template <typename> class AL = std::allocator
>
class cLockFreeQueue
{
private:
#pragma pack(push)
#pragma pack(MEMORY_ALLOCATION_ALIGNMENT)
struct NODE
{
NODE* Next;
T Data;
};
#pragma pack(pop)
NODE* m_Head; ///< Å¥ Çìµå.
NODE* m_Tail; ///< Å¥ Å×ÀÏ.
AL<NODE> m_Allocator; ///< ¸Þ¸ð¸® ÇÒ´çÀÚ.
public:
/// \brief »ý¼ºÀÚ.
cLockFreeQueue()
{
m_Head = m_Allocator.allocate(1);
m_Allocator.construct(m_Head, NODE());
m_Tail = m_Head;
m_Head->Next = NULL;
m_Tail->Next = NULL;
}
/// \brief ¼Ò¸êÀÚ.
~cLockFreeQueue()
{
Clear();
m_Allocator.destroy(m_Head);
m_Allocator.deallocate(m_Head, 0);
}
public:
/// \brief µ¥ÀÌÅ͸¦ Ãß°¡ÇÑ´Ù.
/// \param data Ãß°¡ÇÒ µ¥ÀÌÅÍ.
void Push(const T& data)
{
NODE* oldTail = NULL;
NODE* oldNext = NULL;
// »õ·Î¿î ³ëµå¸¦ ÇÒ´çÇÑ´Ù.
NODE* node = m_Allocator.allocate(1);
m_Allocator.construct(node, NODE());
node->Next = NULL;
node->Data = data;
// Å×ÀÏ ÂÊÀÇ Next ¸µÅ©°¡ »õ·Î¿î ³ëµå¸¦ °¡¸£Å³ ¶§±îÁö ·çÇÁ¸¦ µ·´Ù.
bool addedNewNode = false;
while (!addedNewNode)
{
// Æ÷ÀÎÅ͵éÀÇ Ä«ÇǸ¦ ¸¸µç´Ù.
// ´Ù¸¥ ½º·¹µå¿¡¼ Å×ÀÏ Æ÷ÀÎÅ͸¦ º¯°æÇÒ ¼ö Àֱ⠶§¹®ÀÌ´Ù.
oldTail = m_Tail;
oldNext = oldTail->Next;
// Å×ÀÏ Æ÷ÀÎÅͰ¡ º¯°æµÇÁö ¾Ê¾Ò´Ù¸é...
if (m_Tail == oldTail)
{
// Å×ÀÏÀÇ Next Æ÷ÀÎÅͰ¡ NULLÀ̶ó¸é...
if (oldNext == NULL)
{
// Å×ÀÏÀÇ Next Æ÷ÀÎÅÍ º¯°æÀ» ½ÃµµÇÑ´Ù.
addedNewNode = CAS(&(m_Tail->Next), NULL, node);
}
// Å×ÀÏÀÇ Next Æ÷ÀÎÅͰ¡ NULLÀÌ ¾Æ´Ï¶ó´Â ¸»Àº,
// ´Ù¸¥ ½º·¹µå¿¡¼ ³ëµå¸¦ Ãß°¡Çϰí ÀÖ´Â ÁßÀ̶ó´Â ¸»ÀÌ´Ù.
// ±×·¯¹Ç·Î Å×ÀÏ Æ÷ÀÎÅÍ º¯°æÀ» ½ÃµµÇÑ´Ù.
else
{
CAS(&m_Tail, oldTail, oldNext);
}
}
}
// Å×ÀÏ Æ÷ÀÎÅͰ¡ »õ·Î¿î ³ëµå¸¦ °¡¸£Å°µµ·Ï º¯°æÇÑ´Ù. ½ÇÆÐÇÒ ¼öµµ Àִµ¥,
// ´Ù¸¥ ½º·¹µå¿¡¼ ó¸®ÇØÁÙ °ÍÀ̹ǷΠ°ÆÁ¤ÇÒ ÇÊ¿ä ¾ø´Ù.
CAS(&m_Tail, oldTail, node);
}
/// \brief µ¥ÀÌÅ͸¦ »Ì¾Æ³½´Ù.
/// \param data »Ì¾Æ³½ µ¥ÀÌÅ͸¦ ¾µ º¯¼ö.
/// \return bool µ¥ÀÌÅ͸¦ »Ì¾Æ³½ °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇϰí,
/// µ¥ÀÌÅͰ¡ ¾ø´Â °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
bool Pop(T& data)
{
NODE* oldHead = NULL;
NODE* oldTail = NULL;
NODE* oldHeadNext = NULL;
// Çìµå Æ÷ÀÎÅͰ¡ ´ÙÀ½ ³ëµå¸¦ °¡¸£Å³ ¶§±îÁö ·çÇÁ¸¦ µ·´Ù.
bool advancedHead = false;
while (!advancedHead)
{
// Æ÷ÀÎÅ͵éÀÇ Ä«ÇǸ¦ ¸¸µç´Ù.
// ´Ù¸¥ ½º·¹µå¿¡¼ Å×ÀÏ Æ÷ÀÎÅ͸¦ º¯°æÇÒ ¼ö Àֱ⠶§¹®ÀÌ´Ù.
oldHead = m_Head;
oldTail = m_Tail;
oldHeadNext = oldHead->Next;
// Çìµå Æ÷ÀÎÅͰ¡ º¯°æµÇÁö ¾Ê¾Ò´Ù¸é...
if (oldHead == m_Head)
{
// Çìµå Æ÷ÀÎÅͰ¡ Å×ÀÏ Æ÷ÀÎÅÍ¿Í °°´Ù¸é...
if (oldHead == oldTail)
{
// ÇìµåÀÇ Next Æ÷ÀÎÅͰ¡ NULLÀ̶ó¸é...
if (oldHeadNext == NULL)
{
// »Ì¾Æ³¾ ¾ÆÀÌÅÛÀÌ Á¸ÀçÇÏÁö ¾Ê´Â´Ù.
return false;
}
// ÇìµåÀÇ Next Æ÷ÀÎÅͰ¡ NULLÀÌ ¾Æ´Ï°í,
// Çìµå°¡ Å×Àϰú °°Áö ¾Ê´Ù´Â ¸»Àº,
// ´Ù¸¥ ½º·¹µå¿¡¼ Å×ÀÏ¿¡´Ù ³ëµå¸¦ Ãß°¡Çϰí ÀÖ´Ù´Â ¸»ÀÌ´Ù.
// Å×ÀÏ Æ÷ÀÎÅ͸¦ ¾÷µ¥ÀÌÆ®ÇÑ´Ù.
CAS(&m_Tail, oldTail, oldHeadNext);
}
// Çìµå Æ÷ÀÎÅͰ¡ Å×ÀÏ Æ÷ÀÎÅÍ¿Í ´Ù¸£´Ù¸é...
else
{
// »Ì¾Æ³¾ ¾ÆÀÌÅÛÀ» º¹»çÇϰí, Çìµå Æ÷ÀÎÅ͸¦ µÚ·Î ¿Å±ä´Ù.
data = oldHeadNext->Data;
advancedHead = CAS(&m_Head, oldHead, oldHeadNext);
}
}
}
m_Allocator.destroy(oldHead);
m_Allocator.deallocate(oldHead, 0);
return true;
}
/// \brief ¸ðµç µ¥ÀÌÅ͸¦ »èÁ¦ÇÑ´Ù.
void Clear()
{
T data;
while (Pop(data))
;
}
private:
/// Compare and Swap
bool CAS(NODE** location, NODE* comperand, NODE* newValue)
{
return comperand == InterlockedCompareExchangePointer(
reinterpret_cast<volatile PVOID*>(location), newValue, comperand
);
}
/// \brief º¹»ç »ý¼º ±ÝÁö.
cLockFreeQueue(const cLockFreeQueue&) {}
/// \brief ´ëÀÔ ±ÝÁö.
cLockFreeQueue& operator = (const cLockFreeQueue&) { return *this; }
};
3 ¸µÅ©
SeriousMoin v1 (koMoinMoin 1.0a4 Modified)