Click here to Skip to main content
15,886,199 members
Articles / Programming Languages / C#

Concurrency Hazards: False Sharing

Rate me:
Please Sign up or sign in to vote.
4.95/5 (110 votes)
10 Jan 2010CPOL13 min read 311.7K   1K   115  
False sharing and how to detect and avoid it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Threading;
using System.Runtime.InteropServices;

namespace FalseSharingDemo
{
	class Worker
	{
		const int ITERS = ( int ) 1e7;

		int _ThreadCount = 0;
		bool _OneWriter = false;
		int _Padding = 0;
		int _Spacing = 0;
		int _Affinity = 0;

		public Worker( int threadCount, bool oneWriter, int padding, int spacing, int affinity )
		{
			_ThreadCount = threadCount;
			_OneWriter = oneWriter;
			_Padding = padding;
			_Spacing = spacing;
			_Affinity = affinity;
		}

		[DllImport( "kernel32.dll" )]
		static extern IntPtr GetCurrentThread();

		[DllImport( "kernel32.dll" )]
		static extern UIntPtr SetThreadAffinityMask( IntPtr hThread, UIntPtr dwThreadAffinityMask );

		public TimeSpan Work()
		{
			var data = new int[ _Padding + ( _ThreadCount * _Spacing ) ];
			Array.Clear( data, 0, data.Length );

			var iters = ITERS / _ThreadCount;
			//var iters = ITERS;

			using ( var mre = new ManualResetEvent( false ) )
			using ( var countdown = new CountdownEvent( _ThreadCount ) )
			{
				TimeSpan[] tss = new TimeSpan[ Environment.ProcessorCount ];

				for ( int i = 0 ; i < _ThreadCount ; i++ )
				{
					int iThread = i;

					if ( !_OneWriter || iThread == 0 )
					{
						new Thread( () =>
						{
							SetThreadAffinityMask( GetCurrentThread(), new UIntPtr( 1u << ( iThread * _Affinity ) ) );

							var offset = _Padding + ( iThread * _Spacing );

							mre.WaitOne();

							for ( int x = 0 ; x < iters ; x++ ) data[ offset ]++;

							countdown.Signal();

						} ) { IsBackground = true, Priority = ThreadPriority.Highest }.Start();
					}
					else
					{
						new Thread( () =>
						{
							SetThreadAffinityMask( GetCurrentThread(), new UIntPtr( 1u << ( iThread * _Affinity ) ) );

							var offset = _Padding + ( iThread * _Spacing );
							int dummy = 0;

							mre.WaitOne();

							for ( int x = 0 ; x < iters ; x++ ) dummy = data[ offset ];

							countdown.Signal();

						} ) { IsBackground = true, Priority = ThreadPriority.Highest }.Start();
					}
				}

				Thread.Sleep( 100 );

				var sw = Stopwatch.StartNew();

				mre.Set();

				countdown.Wait();

				var ts = sw.Elapsed;

				Trace.WriteLine( "False : " + data.Sum( i => ( long ) i ).ToString( "N0" ) + " in " + ts.TotalSeconds + " secs" );

				return ts;
			}
		}
	}
}

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
United Kingdom United Kingdom
I discovered C# and .NET 1.0 Beta 1 in late 2000 and loved them immediately.
I have been writing software professionally in C# ever since

In real life, I have spent 3 years travelling abroad,
I have held a UK Private Pilots Licence for 20 years,
and I am a PADI Divemaster.

I now live near idyllic Bournemouth in England.

I can work 'virtually' anywhere!

Comments and Discussions