Click here to Skip to main content
15,886,137 members
Articles / Programming Languages / C++

Testing simple concurrent containers

Rate me:
Please Sign up or sign in to vote.
5.00/5 (12 votes)
25 Oct 2009CPOL10 min read 50.4K   404   40  
This article illustrates simple approaches and test results when creating containers with concurrent flavor and running on a multi-core PC.
/*
This is the code of the Pool_of_shared_elements crash test. The purpose of this code is to show
that the minimum size of the pool Pool_of_shared_elements is (2*number_of_threads-1).
If the size of the pool is smaller, the pool may crash. The probability of such failure is low
for large containers - and it might be difficult to spot it out when debugging the application.
This code simulates holding of two pool elements by one thread, when a shared pool element is
already popped by another thread.
*/

#pragma once
#include "pool_t.h"
#include <map>

template <typename Entry_t, WORD number_of_threads,
const size_t pool_size = (2*number_of_threads-1)/* this is the minimum size of the pool*/> 

class CACHE_ALIGN Pool_of_shared_elements_crash_test: 
private Pool_t<Entry_t, pool_size - 1 /*set the pool_size smaller than (2*number_of_threads-1) to crash it*/>
{
public:
	WORD pop(volatile LONG& reference_counter)
	{
		LONG i;
		LONG j;
		LONG exch_counter;

		WORD new_index = static_cast<WORD>(__super::pop());

		if (new_index == 0)
		{
			::MessageBox(0, _T("There are no free elements in the pool."), 
				_T("Pool_of_shared_elements_crash_test application."), 0);
			return 0; /* error */ 
		}
		else
		{
		}

		j = acquire_read(reference_counter);
		do
		{
			exch_counter = (HIWORD(j) == 0)? ((LONG)new_index << 16) | (LOWORD(j) + 1) : j + 1;
			i = j;
			j = acquire_interlocked_compare_exchange(&reference_counter,
							exch_counter,
							i);
			PAUSE

		} while(i != j);

		WORD index = HIWORD(exch_counter); 

		if ( index != new_index)
		{
			////////////////////////////
			// crash code
			Pool_element_pair pool_pair;
			//keep indexes for debug purposes, to see the pool elements which are already popped from the pool
			pool_pair.m_index1 = index;
			pool_pair.m_index2 = new_index;
			::EnterCriticalSection(&m_cs);
			bool rc = m_pool_pairs.insert(std::map<int, Pool_element_pair>::value_type(index, pool_pair)).second;
			::LeaveCriticalSection(&m_cs);
			if (true == rc)
			{
				//now, one thread holds two pool elements
				::Sleep(INFINITE);
			}
			// end crash code
			////////////////////////////

			__super::push( new_index );
		}
		else
		{
		}

		return index;
	}

	void push(WORD index, volatile LONG& reference_counter)
	{
		LONG counter = interlocked_decrement_release(&reference_counter);
		if (LOWORD(counter) == 0)
		{
			if ( counter == acquire_interlocked_compare_exchange(&reference_counter, 0x0, counter))
			{
				__super::push( index );
			}
			else
			{
			}
		}
		else
		{
		}
	}

	inline Entry_t* get(WORD index)
	{
		return __super::get(index);
	}

	////////////////////////////
	// crash code
	struct Pool_element_pair {
		int m_index1;
		int m_index2;
	};
	std::map<int, Pool_element_pair> m_pool_pairs;
	CRITICAL_SECTION m_cs;
	Pool_of_shared_elements_crash_test() {	::InitializeCriticalSection(&m_cs); }
	~Pool_of_shared_elements_crash_test() {	::DeleteCriticalSection(&m_cs); }
	// end crash code
	////////////////////////////

};

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)


Written By
Software Developer
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions