Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 564
  • Last Modified:

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

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

0
Alexey Fedorov
Asked:
Alexey Fedorov
  • 2
  • 2
1 Solution
 
TommySzalapskiCommented:
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.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
"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?
0
 
Alexey FedorovSoftware developerAuthor Commented:
Yes, Idle_Mind: exc. "collection was modified" is impossible. Readers don't wait on any locking and once a reader had acquired the "_users" it shouldn't reflect added/removed items.

I meant the object ref. "_users" is read in unsafe way and supposed it might be partially changed and invalid.

But, it seems Interlocked.Exchange protects well: it changes obj. ref. atomicity (by one CPU command). So, object reference "_users" is always valid.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Gotcha...so you weren't talking about the contents, but the reference itself.  =)
0
 
Alexey FedorovSoftware developerAuthor Commented:
The concurent shared resource "_users" access scheme is originally valid and complete.
0

Featured Post

Microsoft Certification Exam 74-409

VeeamĀ® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now