We help IT Professionals succeed at work.

Check out our new AWS podcast with Certified Expert, Phil Phillips! Listen to "How to Execute a Seamless AWS Migration" on EE or on your favorite podcast platform. Listen Now

x

Effective locking on a collection: multiple readers and writers (.Net, C#)

Alexey Fedorov
on
Medium Priority
611 Views
Last Modified: 2012-05-11
Hi, guys!

I think about a most effective way to access a List on multiple threads at one time, for reading and updating (adding, removing elements). The peculiarity is:
  1) List is rarely updated;
  2) List is read very offten (almost continiously).

So I decided neither to use .Net 4 ConcurrentQueue<T> nor "lock" on the list, nor ReaderWriterLock to boost up the performance.
I use no lock at all for readers, and I use the lock on separate object for writers.

But, I'm in doundbt about how to safely access the list var. in readers. I marked the list as volatile and use Interlocked.Exchange in writers, but in readers I use direct accessing.

I'm affraid: one time a reader might acquire a partially updated object ref.  _users.

private volatile List<UserConnection> _users = new List<UserConnection>();
private readonly object _lockUsers = new object();

private void AddUserConnection (UserConnection conn)
{
	lock (_lockUsers)
	{
		List<UserConnection> newList = new List<UserConnection>(_users) ;
                newList.Add(conn);
		Interlocked.Exchange(ref _users, newList);			
	}
}

private void RemoveUserConnection (UserConnection conn)
{
	lock (_lockUsers)
	{
		List<UserConnection> newList = new List<UserConnection>(_users);
		newList.Remove(conn);
		Interlocked.Exchange(ref _users, newList);
	}
}


void Distribute (someData)
{
	foreach (UserConnection usr in _users)
	{
		//...do some processing
	}
}

Open in new window

Comment
Watch Question

CERTIFIED EXPERT
Awarded 2010
Top Expert 2013

Commented:
Did you test the ReaderWriterLock for performance? It does exactly what you want and should be fast.
If you still don't like it, then create a token (or something) that does use the ReaderWriterLock. Then have the readers and writers check out the token before starting to read the actual list. If the token is held by any readers, the writer waits and vice versa. This way you can still use all the direct memory stuff that you are using, but you get the power and siplicity of the built in mutual exclusion.
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
CERTIFIED EXPERT
Top Expert 2009

Commented:
"I'm affraid: one time a reader might acquire a partially updated object ref.  _users."

I just did a quick test and the foreach() in distribute did not throw a "collection was modified" exception, did not see new items added, and did not reflect when items were deleted.  It completed the enumeration using the collection as it was when the foreach() started...is that the behavior you're looking for?
Software developer
Commented:
Unlock this solution with a free trial preview.
(No credit card required)
Get Preview
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
CERTIFIED EXPERT
Top Expert 2009

Commented:
Gotcha...so you weren't talking about the contents, but the reference itself.  =)
Alexey FedorovSoftware developer

Author

Commented:
The concurent shared resource "_users" access scheme is originally valid and complete.
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a free trial preview!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.