Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Testing simple concurrent containers

, 25 Oct 2009 CPOL
This article illustrates simple approaches and test results when creating containers with concurrent flavor and running on a multi-core PC.
container_locks.zip
Container_locks
src
Testing_simple_concurrent_containers.pdf
VC9
container_locks.vcproj.val-PC.val.user
Debug
tbb_debug.dll
Debug64
tbb_debug.dll
Release
tbb.dll
Release64
tbb.dll
/*
Copyright (c) 2009 Valery Grebnev.
CPOL (Code Project Open License) Licensed http://www.codeproject.com/info/cpol10.aspx
*/


#pragma once 

#include "interlocked.h"
#include "pool_t.h"
//#include "pool_crash_test.h"

/*
Both "ref_shared_lock_t" and "ref_exclusive_lock_t" are used for 
container global scope operations. The "ref_exclusive_lock_t" is used
when the container's structure is changed (inserting/deleting elements).
The "ref_shared_lock_t" is used when accessing the container's elements
(reading or updating values).
*/

template <typename lock_t, typename rw_status>
class shared_lock_t : public lock_t
{
public:
	shared_lock_t(volatile rw_status& status) : lock_t(status)
	{
		acquireLockShared();
	}
	~shared_lock_t()
	{
		releaseLockShared();
	}
private:
	shared_lock_t& operator=(const shared_lock_t&); //C4512 warning
};

template <typename lock_t>
class ref_shared_lock_t
{
public:
	ref_shared_lock_t(lock_t& lock) : m_lock(lock)
	{
		m_lock.acquireLockShared();
	}
	~ref_shared_lock_t()
	{
		m_lock.releaseLockShared();
	}
private:
	lock_t& m_lock;
	ref_shared_lock_t& operator=(const ref_shared_lock_t&); //C4512 warning
};

template <typename lock_t, typename rw_status>
class exclusive_lock_t : public lock_t
{
public:
	exclusive_lock_t(volatile rw_status& status) : lock_t(status)
	{
		acquireLockExclusive();
	}
	~exclusive_lock_t()
	{
		releaseLockExclusive();
	}
private:
	exclusive_lock_t& operator=(const exclusive_lock_t&); //C4512 warning
};

template <typename lock_t>
class ref_exclusive_lock_t
{
public:
	ref_exclusive_lock_t(lock_t& lock) : m_lock(lock)
	{
		m_lock.acquireLockExclusive();
	}
	~ref_exclusive_lock_t()
	{
		m_lock.releaseLockExclusive();
	}
private:
	lock_t& m_lock;
	ref_exclusive_lock_t& operator=(const ref_exclusive_lock_t&); //C4512 warning
};


/*
Both "ref_shared_pool_lock_t" and "ref_exclusive_pool_lock_t" are used 
for element scope operations. When using these locks, the container is already
locked by a global scope lock. The "ref_exclusive_pool_lock_t" is used
when a container element value is updated. The "ref_shared_pool_lock_t" is used
when a container element value is only read.
*/

template <typename lock_t, typename pool_of_locks_t>
class ref_shared_pool_lock_t
{
public:
	ref_shared_pool_lock_t(volatile LONG& reference_counter, pool_of_locks_t& lock_pool) 
		: m_reference_counter(reference_counter), m_pool_of_locks(lock_pool), m_lock_index(0), m_plock(NULL)
	{
		m_lock_index = m_pool_of_locks.pop(reference_counter);
		m_plock = m_pool_of_locks.get(m_lock_index);
		m_plock->acquireLockShared();
	}
	~ref_shared_pool_lock_t()
	{
		m_plock->releaseLockShared();
		m_pool_of_locks.push(m_lock_index, m_reference_counter);
	}
private:
	
	volatile LONG&		m_reference_counter;
	pool_of_locks_t&	m_pool_of_locks;
	lock_t*				m_plock;
	WORD				m_lock_index;

	ref_shared_pool_lock_t& operator=(const ref_shared_pool_lock_t&); //C4512 warning
};

template <typename lock_t, typename pool_of_locks_t>
class ref_exclusive_pool_lock_t
{
public:
	ref_exclusive_pool_lock_t(volatile LONG& reference_counter, pool_of_locks_t& lock_pool) 
		: m_reference_counter(reference_counter), m_pool_of_locks(lock_pool), m_lock_index(0), m_plock(NULL)
	{
		m_lock_index = m_pool_of_locks.pop(reference_counter);
		m_plock = m_pool_of_locks.get(m_lock_index);
		m_plock->acquireLockExclusive();
	}
	~ref_exclusive_pool_lock_t()
	{
		m_plock->releaseLockExclusive();
		m_pool_of_locks.push(m_lock_index, m_reference_counter);
	}
private:
	
	volatile LONG&		m_reference_counter;
	pool_of_locks_t&	m_pool_of_locks;
	lock_t*				m_plock;
	WORD				m_lock_index;

	ref_exclusive_pool_lock_t& operator=(const ref_exclusive_pool_lock_t&); //C4512 warning
};

/*
"Container_locker_t" is used to for both global and element scope operations:

- When changing the container structure (inserting/deleting elements),
a thread calls the Container_locker_t::Exclusive_lock.

- When changing an element of the container, the thread uses a two-step lock �
first it calls the Container_locker_t::Shared_lock (a global scope lock),
then it calls the Container_locker_t::Element_exclusive_lock (an element scope lock).

- When reading an element of the container, the thread uses the two-step lock �
first it calls the Container_locker_t::Shared_lock (a global scope lock),
then it calls the Container_locker_t::Element_shared_lock (an element scope lock).
*/

template <typename Lock_type, WORD number_of_threads>
struct CACHE_ALIGN Container_locker_t
{
	typedef ref_exclusive_lock_t<Lock_type> Exclusive_lock;
	typedef ref_shared_lock_t<Lock_type> Shared_lock;
	
	typedef Pool_of_shared_elements<Lock_type, number_of_threads> Pool_of_locks;
	//typedef Pool_of_shared_elements_crash_test<Lock_type, number_of_threads> Pool_of_locks;

	typedef ref_exclusive_pool_lock_t<Lock_type, Pool_of_locks> Element_exclusive_lock;
	typedef ref_shared_pool_lock_t<Lock_type, Pool_of_locks> Element_shared_lock;

	template <typename value_type>
	struct internal_value
	{
		internal_value(value_type value): m_lock(0), m_value(value) 
		{
		}
		volatile LONG CACHE_ALIGN m_lock;
		CACHE_PADDING(2)
		value_type m_value;
	};

	CACHE_PADDING(1)
	Pool_of_locks CACHE_ALIGN m_element_locks;
	CACHE_PADDING(2)
	Lock_type CACHE_ALIGN m_global_scope_lock;

	Container_locker_t& operator=(const Container_locker_t&); //C4512 warning
};

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Valery Grebnev
Software Developer
Canada Canada
No Biography provided

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141216.1 | Last Updated 25 Oct 2009
Article Copyright 2009 by Valery Grebnev
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid