The ramblings of a disgruntled geek!!

Tuesday, November 25, 2008

A Custom SpinLock based CriticalSection Implementation



Just something I implemented for fun :)


#include "stdafx.h"
#include <intrin.h>
#include <process.h>
#include <vector>
#include <utility>
#include <algorithm>
#include <iostream>
#pragma intrinsic (_InterlockedCompareExchange, _InterlockedExchange)
namespace DotFermion
{
class CCriticalSection
{
enum { LOCK_IS_FREE = 0, LOCK_IS_TAKEN = 1 };
private:
long lock;
long ownerThreadId;
long acquireCount;
public:
CCriticalSection():
lock(LOCK_IS_FREE),ownerThreadId(-1),acquireCount(0){}
~CCriticalSection()
{
Release();
}
//Non-recursive Acquire. Once its called, all threads, even the one owning the lock block on this lock.
//Even a subsequent AcquireRecursive call after this one blocks.
void Acquire()
{
while (_InterlockedExchange(&lock, LOCK_IS_TAKEN) == LOCK_IS_TAKEN);
}
//Recursive Acquire. It doesn't block if called multiple times from the same thread.
void AcquireRecursive(long threadId)
{
if(ownerThreadId != -1 && threadId == ownerThreadId)
{
_InterlockedIncrement(&acquireCount);
return;
}
Acquire ();
_InterlockedExchange(&ownerThreadId, threadId );
_InterlockedIncrement(&acquireCount);
}

void Release()
{
if(acquireCount > 1)
{
_InterlockedDecrement(&acquireCount);
return;
}
_InterlockedExchange(&acquireCount, 0);
_InterlockedExchange(&ownerThreadId, -1);
_InterlockedExchange(&lock, LOCK_IS_FREE);
}
};

}

#define LIST_POS = 4;
#define INDEX_POS = 8;

typedef void (*LPFNTHREADPROC) (void*);
typedef std::vector<uintptr_t> THREADLIST;
typedef THREADLIST* PTHREADLIST;
typedef struct _args_t
{
DotFermion::CCriticalSection* pCs;
PTHREADLIST pThreadList;
int index;
} args_t;

THREADLIST g_ThreadList;
int g_ThreadCount = 0;
int g_SharedCounter = 0;

void ThreadProc(void* argList)
{
args_t* args = (args_t*)argList;
args->pCs->AcquireRecursive((long)args->pThreadList->at(args->index));
g_SharedCounter++;
args->pCs->AcquireRecursive((long)args->pThreadList->at(args->index));
g_SharedCounter++;
args->pCs->Release();
args->pThreadList->at(args->index) = -1L;
g_ThreadCount--;
args->pCs->Release();
delete args;
}

int StartThreads ( int n, PTHREADLIST pThreadList, DotFermion::CCriticalSection* cs )
{
pThreadList->resize(n);
for ( int i = 0 ; i < n ; i ++ )
{
args_t* args = new args_t;
if ( args == NULL ) continue;
args->pCs = cs;
args->pThreadList = pThreadList;
args->index = i;
uintptr_t threadId = _beginthread(ThreadProc, 0, (void*)args);
if ( threadId != -1L )
{
cs->Acquire();
pThreadList->at(i) = threadId;
g_ThreadCount ++;
cs->Release();
}
}
return g_ThreadCount;
}


void Join (int* threadCount)
{
while ( *threadCount );
}

int _tmain(int argc, _TCHAR* argv[])
{
DotFermion::CCriticalSection cs;
StartThreads(100, &g_ThreadList, &cs);
Join(&g_ThreadCount);
std::cout << g_SharedCounter << std::endl;
return 0;
}



Keyboard

Keyboard
Keyboard

Blog Reading Level

blog readability test
Powered By Blogger

VerveEarth