Thread Sincronization Issue: Aborting thread with locked resources
-
Hi. I've a multithreaded service application with many threads accessing a comom resource. I have a typical Readers/Writers environment, where many threads may read at the same time but only one can write to the resource, exclusively. The thing is, whenever two threads (or more) asks for writing permission, I do not need to wait for the first thread to finish, I can just abort it (the first thread is no longer needed) and execute the second thread. Since writing is an expensive operation, it's desirable that I abort the first thread and execute the second. So, here's my doubt: if I abort a thread that holds a lock, will it release the lock? My simplified code looks like this:
private static System.Threading.Thread WritingThread =
System.Threading.Thread(MyClass.PerformWriting)private void TryWrite()
{
If (WritingThread.IsAlive)
WritingThread.Abort();WritingThread.Start();
}
private void PerformWriting()
{
MyReaderWriterLockSlim.EnterWriteLock();try{
//writing operation - takes a long time
}
finally{
MyReaderWriterLockSlim.ExitWriteLock();
}
}So here's the deal. I have a commom fixed writing thread for everybody, so I can test if the thread is already running, and if is, I can just abort it and initiate it again. This get the effect of aborting the first writing and executing the second. Whenever a thread needs to write to the resouce, it just calls the TryWrite function. The original calling thread doesn't need to wait the end of the operation, so it returns and finishes. But, since "writing operation" takes a long time, it is more likely that the WritingThread will be aborted when it is writing, that is, when it holds the lock. Is that code ok, or it will deadlock when the thread gets aborted in the middle of the writing?
Regards, Leonardo Muzzi
-
Hi. I've a multithreaded service application with many threads accessing a comom resource. I have a typical Readers/Writers environment, where many threads may read at the same time but only one can write to the resource, exclusively. The thing is, whenever two threads (or more) asks for writing permission, I do not need to wait for the first thread to finish, I can just abort it (the first thread is no longer needed) and execute the second thread. Since writing is an expensive operation, it's desirable that I abort the first thread and execute the second. So, here's my doubt: if I abort a thread that holds a lock, will it release the lock? My simplified code looks like this:
private static System.Threading.Thread WritingThread =
System.Threading.Thread(MyClass.PerformWriting)private void TryWrite()
{
If (WritingThread.IsAlive)
WritingThread.Abort();WritingThread.Start();
}
private void PerformWriting()
{
MyReaderWriterLockSlim.EnterWriteLock();try{
//writing operation - takes a long time
}
finally{
MyReaderWriterLockSlim.ExitWriteLock();
}
}So here's the deal. I have a commom fixed writing thread for everybody, so I can test if the thread is already running, and if is, I can just abort it and initiate it again. This get the effect of aborting the first writing and executing the second. Whenever a thread needs to write to the resouce, it just calls the TryWrite function. The original calling thread doesn't need to wait the end of the operation, so it returns and finishes. But, since "writing operation" takes a long time, it is more likely that the WritingThread will be aborted when it is writing, that is, when it holds the lock. Is that code ok, or it will deadlock when the thread gets aborted in the middle of the writing?
Regards, Leonardo Muzzi
Hi, aborting a thread is a bad idea, as it (1) may not occur right away (e.g. when inside some I/O operations) and (2) will get kicked out in an unknown state, without getting a chance for cleaning up after itself. so the recommendation is not to abort at all, rather to implement a cooperative thread exit scheme, where the thread regularly checks a flag to make sure it should continue its work or exit. And as you would abort a thread to start a similar thread, there is no need to do any thread operation at all, just tell the thread to abandon its current job and start executing the new job. :)
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get. Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
-
Hi, aborting a thread is a bad idea, as it (1) may not occur right away (e.g. when inside some I/O operations) and (2) will get kicked out in an unknown state, without getting a chance for cleaning up after itself. so the recommendation is not to abort at all, rather to implement a cooperative thread exit scheme, where the thread regularly checks a flag to make sure it should continue its work or exit. And as you would abort a thread to start a similar thread, there is no need to do any thread operation at all, just tell the thread to abandon its current job and start executing the new job. :)
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get. Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
Good ! :) I'll try implementing the "restart flag" inside the writing operation. But, let's say I can not interfere in the writing code (I don't know if I can, not my implementation), so I can't change the writing operation to test a flag eventually. Any other ideas? Thanks !
Regards, Leonardo Muzzi
-
Good ! :) I'll try implementing the "restart flag" inside the writing operation. But, let's say I can not interfere in the writing code (I don't know if I can, not my implementation), so I can't change the writing operation to test a flag eventually. Any other ideas? Thanks !
Regards, Leonardo Muzzi
I'm thinking about implementing another thread that just sleeps for a while and checks for the flag, and abort the WritingThread if it finds the restart flag true. This new thread would hold the lock and therefore I can make sure it will release it. Still, I'm aborting threads and creating new ones. Is it good?
Regards, Leonardo Muzzi
-
Good ! :) I'll try implementing the "restart flag" inside the writing operation. But, let's say I can not interfere in the writing code (I don't know if I can, not my implementation), so I can't change the writing operation to test a flag eventually. Any other ideas? Thanks !
Regards, Leonardo Muzzi
This[^] is the best I ever found about .NET threading. :)
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get. Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
-
I'm thinking about implementing another thread that just sleeps for a while and checks for the flag, and abort the WritingThread if it finds the restart flag true. This new thread would hold the lock and therefore I can make sure it will release it. Still, I'm aborting threads and creating new ones. Is it good?
Regards, Leonardo Muzzi
You don't need a thread to hold a lock; you can implement the thread stuff and the lock inside a class. BTW: when you reply to yourself, you're the one getting the mail notification... :)
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get. Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
-
This[^] is the best I ever found about .NET threading. :)
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get. Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
Excelent text! This is what I needed to know: "All catch/finally blocks are honored, and never aborted mid-stream" So the first code would work. I'll check if I can change the writing operation to test a restart flag anyway! Thanks for the help ! (sorry for the self-reply)
Regards, Leonardo Muzzi
-
Excelent text! This is what I needed to know: "All catch/finally blocks are honored, and never aborted mid-stream" So the first code would work. I'll check if I can change the writing operation to test a restart flag anyway! Thanks for the help ! (sorry for the self-reply)
Regards, Leonardo Muzzi
You're welcome. :)
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get. Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
-
Excelent text! This is what I needed to know: "All catch/finally blocks are honored, and never aborted mid-stream" So the first code would work. I'll check if I can change the writing operation to test a restart flag anyway! Thanks for the help ! (sorry for the self-reply)
Regards, Leonardo Muzzi
"All catch/finally blocks are honored, and never aborted mid-stream..." ...but code which relies upon certain instructions not throwing exceptions may be broken if they do so. See the article's comments about 'using'. By the sound of it, using abort exceptions doesn't sound very safe. Using interrupt would seem much safer, provided that any time-consuming loops that don't engage in managed sleeping test a flag for whether they should exit. The "using" directive is nice in many ways--it's too bad that there are so many wrinkles when using it. If a constructor could take a byRef parameter indicating where the new object should be stored, and if it could store the newly-created object there before leaving its outermost try/catch block, one could emulate a 'Using' in such a way as to avoid leaving dangling resources in case of an abort. Unfortunately, I don't know any way to make anything remotely like that work as smoothly as "using". Too bad iDisposable seems to have been an afterthought (unlike Finalize, which is common to all objects). If Finalize took a parameter which indicated whether to perform a garbage-collect cleanup, explicit disposal, or failed-object-creation cleanup (objects that wanted to receive a garbage-collect cleanup would have to register) that would have simplified a lot of things.