Claudio Ferraro
Claudio Ferraro

Reputation: 4721

When to use the lock thread in C#?

I have a server which handles multiple incoming socket connections and creates 2 different threads which store the data in XML format.

I was using the lock statement for thread safety almost in every event handler called asyncronously and in the 2 threads in different parts of code. Sadly using this approach my application significantly slows down.

I tried to not use lock at all and the server is very fast in execution, even the file storage seems to boost; but the program crashes for reasons I don't understand after 30sec - 1min. of work.

So. I thought that the best way is to use less locks or to use it only there where's strictly necessary. As such, I have 2 questions:

  1. Is the lock needed when I write to the public accessed variables (C# lists) only or even when I read from them ?

  2. Is the lock needed only in the asyncronous threads created by the socket handler or in other places too ?

Someone could give me some practical guidelines, about how to operate. I'll not post the whole code this time. It hasn't sense to post about 2500 lines of code.

Upvotes: 27

Views: 6007

Answers (5)

ΩmegaMan
ΩmegaMan

Reputation: 31616

Is the lock needed when I write to the public accessed variables (C# lists) only or even when I read from them ?

Yes (even when you read).

Is the lock needed only in the asyncronous threads created by the socket handler or in other places too ?

Yes. Wherever code accesses a section of code which is shared, always lock.


This sounds like you may not be locking individual objects, but locking one thing for all lock situations.

If so put in smart discrete locks by creating individual unique objects which relate and lock only certain sections at a time, which don't interfere with other threads in other sections.

Here is an example:

// This class simulates the use of two different thread safe resources and how to lock them
// for thread safety but not block other threads getting different resources.
public class SmartLocking
{
    private string StrResource1 { get; set; }
    private string StrResource2 { get; set; }

    private object _Lock1 = new object();
    private object _Lock2 = new object();

    public void DoWorkOn1( string change )
    {
        lock (_Lock1)
        {
            _Resource1 = change;
        }
    }

    public void DoWorkOn2( string change2 )
    {
        lock (_Lock2)
        {
            _Resource2 = change2;
        }
    }
}

Upvotes: 33

Eric Lippert
Eric Lippert

Reputation: 660038

You ever sit in your car or on the bus at a red light when there's no cross traffic? Big waste of time, right? A lock is like a perfect traffic light. It is always green except when there is traffic in the intersection.

Your question is "I spend too much time in traffic waiting at red lights. Should I just run the red light? Or even better, should I remove the lights entirely and just let everyone drive through the intersection at highway speeds without any intersection controls?"

If you're having a performance problem with locks then removing locks is the last thing you should do. You are waiting at that red light precisely because there is cross traffic in the intersection. Locks are extraordinarily fast if they are not contended.

You can't eliminate the light without eliminating the cross traffic first. The best solution is therefore to eliminate the cross traffic. If the lock is never contended then you'll never wait at it. Figure out why the cross traffic is spending so much time in the intersection; don't remove the light and hope there are no collisions. There will be.

If you can't do that, then adding more finely-grained locks sometimes helps. That is, maybe you have every road in town converging on the same intersection. Maybe you can split that up into two intersections, so that code can be moving through two different intersections at the same time.

Note that making the cars faster (getting a faster processor) or making the roads shorter (eliminating code path length) often makes the problem worse in multithreaded scenarios. Just as it does in real life; if the problem is gridlock then buying faster cars and driving them on shorter roads gets them to the traffic jam faster, but not out of it faster.

Upvotes: 88

Akrem Osman
Akrem Osman

Reputation: 11

The reason that you need to lock while reading is:

let's say you are making change to one property and it has being read twice while the thread is inbetween a lock. Once right before we made any change and another after, then we will have inconsistent results.

I hope that helps,

Upvotes: 1

Fredrik Ullner
Fredrik Ullner

Reputation: 2156

Always use a lock when you access members (either read or write). If you are iterating over a collection, and from another thread you're removing items, things can go wrong quickly.

A suggestion is when you want to iterate a collection, copy all the items to a new collection and then iterate the copy. I.e.

var newcollection; // Initialize etc.
lock(mycollection)
{
  // Copy from mycollection to newcollection
}

foreach(var item in newcollection)
{
  // Do stuff
}

Likewise, only use the lock the moment you are actually writing to the list.

Upvotes: 2

Muepe
Muepe

Reputation: 671

Basically this can be answered pretty simple:

You need to lock all the things that are accessed by different threads. It actually doesnt really matter if its about reading or writing. If you are reading and another thread is overwriting the data at the same time the data read may get invalid and you possibly are performing invalid operations.

Upvotes: 0

Related Questions