开发者

Threading: allow one thread to access data while blocking others, and then stop blocked threads from executing the same code

imagine the simplest DB access code with some in-memory caching -

if exists in cache  
    return object  
else  
    get from DB  
    add to cache  
    return object  

Now, if the DB access ta开发者_StackOverflow社区kes a second and I have, say, 5 ASP.Net requests/threads hitting that same code within that second, how can I ensure only the first one does the DB call? I have a simple thread lock around it, but that simply queues them up in an orderly fashion, allowing each to call the DB in turn. My data repositories basically read in entire tables in one go, so we're not talking about Get by Id data requests.

Any ideas on how I can do this? Thread wait handles sound almost what I'm after but I can't figure out how to code it.

Surely this must be a common scenario?

Existing pseudocode:

lock (threadLock)  
{  
    get collection of entities using Fluent NHib  
    add collection to cache  
}  

Thanks, Col


You've basically answered your own question. The "lock()" is fine, it prevents the other threads proceeding into that code while any other thread is in there. Then, inside the lock perform your first pseudo-code. Check if it's cached already, if not, retrieve the value and cache it. The next thread will then come in, check the cache, find it's available and use that.


Surely this must be a common scenario?

Not necessarily as common as you may think.

In many similar caching scenarios:

  • the race condition you describe doesn't happen frequently (it requires multiple requests to arrive when the cache is cold)

  • the data returned from the database is readonly, and data returned by multiple requests is essentially interchangeable.

  • the cost of retrieving the database is not so prohibitive that it matters.

But if in scenario you absolutely need to prevent this race condition, then use a lock as suggested by Roger Perkins.


I'd use Monitor/Mutext over lock. Using lock u need to specify a resource (may also use this-pointer, which is not recommended). try the following instead:

Mutext myMutex = new Mutex();
// if u want it systemwide use a named mutex
// Mutext myMutex = new Mutex("SomeUniqueName");

mutex.WaitOne();
// or 
//if(mutex.WaitOne(<ms>))
//{
// //thread has access
//} 
//else 
//{
// //thread has no access
//}
<INSERT CODE HERE>

mutex.ReleaseMutex();


I don't know general solution or established algorithm is exist.

I personally use below code pattern to solve problem like this.

1) Define a integer variable that can be accessed by all thread.

int accessTicket = 0;  

2) Modify code block

int myTicket = accessTicket;

lock (threadLock)
{
    if (myTicket == accessTicket)
    {
        ++accessTicket;
        //get collection of entities using Fluent NHib
        //add collection to cache
    }
}

UPDATE

Purpose of this code is not prevent multiple DB access of duplicate caching. We can do it with normal thread lock.

By using the access ticket like this we can prevent other thread doing again already finished work.

UPDATE#2

LOOK THERE IS lock (threadLock)

Look before comment.

Look carefully before vote down.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜