Threading/Locking

qex

Regular
Joined
Apr 2, 2003
Messages
78
I have a question about locks because I am seeing behavior that does not match what I though was the correct behavior. I thought when you put a lock around code the first instance that ran it would of course get access and then each access after that (while the first instance is still executing the code) would be essentially queued up on that lock waiting for the first to exit. But what I am seeing is that the last one there is the first to get access to the code... which doesn't make sense. If someone can shed some light I would appreciate it. Below is an example of the code and the data that it returned you can see that 4 lines that were logged before the lock and the last one was the first to go inside the lock????

5/11/2005 11:26:43 AM - Data Before Lock: ==============
5/11/2005 11:26:43 AM - Data Before Lock: ==============
5/11/2005 11:26:43 AM - Data Before Lock: ==============
5/11/2005 11:26:43 AM - Data Before Lock: ======= DATE
5/11/2005 11:26:43 AM - Data After Lock: ======= DATE
5/11/2005 11:26:43 AM - Data Before Lock: of BIRTH: 12/
5/11/2005 11:26:43 AM - Data After Lock: of BIRTH: 12/
5/11/2005 11:26:43 AM - Data After Lock: ==============
5/11/2005 11:26:43 AM - Data After Lock: ==============
5/11/2005 11:26:43 AM - Data After Lock: ==============


//lockingObject is a private object contained in the class with this method

Code:
public void getIncomingData(object data)
{
	try
	{
	     myLog.Log(string.Format("Data Before Lock:  {0}",data),true);
	     lock(lockingObject)
	     {
	           myLog.Log(string.Format("Data After Lock:  {0}",data),true);
	           myParser.getIncomingData((string)data);	
	     }
            }
             catch(Exception e)
             {
	          myLog.Log(string.Format("Error in DataCapture getIncomingData: {0}",e.Message));
             }
}
 
I talked to one person and they said that Locks are not guranteed to be executed FIFO, which doesn't make sense to me. Does anyone know if this is the case for sure.

So, how would I get around this. I need the data coming in to be handled in order and the whole reason that this method is in a thread and the need for the locking is that I don't want to hold up the method that is calling it. So I don't want to block the sending thread to wait for the one above because that defeats the whole purpose.

Any Help?
 
Threads get a certain amount of time allocated to them in which they can run. This scheduling is controlled by the OS itself and it has it's own methods of prioritising and allocation resources to threads.
IIRC there is no way to be sure of the order threads will run / access resources.

Depending on exactly what your application is doing there may be an alternate method; have you looked at using a callback / async method to notify the calling method when the thread has completed. Possible even implementing your own queue and processing that in order.
 
Without the code that calls getIncomingData I'd say that this is just Murphy's law at his best: you never know what happens with multithreading.

However, if this happens every time in the exact same sequence there is probably something else going on that requires a bit more information to get clear. Maybe the code that calls getIncomingData might be helpfull ;).
 
Its definitely Murphy!!! It happens at random

here is the code that calls getIncomingData()

My goal was to get out of here as fast as possible because while I'm in this event I'm blocking new data from being read in on my com port.

Thanks for your help... I'm looking to see if maybe I can do this another way.

Code:
private void ComPort_DataAvail(object sender, DataAvailEventArgs e)
{
	try
	{
		ASCIIEncoding AE = new ASCIIEncoding();
		string stringArray = "";
		stringArray = AE.GetString(e.Data());		//Takes the incoming data and turns it into a string
	
		if(portStatus.postest == true)
		{
			DataCaptureArgs mypos = new DataCaptureArgs(port_settings.portID,stringArray,e.Size);
			OnPosTestDataAvail(mypos);
		}
		switch(CurrentState)
		{
			case CapState.start:
				
				DataTimer.Enabled = true;	//Starts the timer when data stops it will fire to clean up and finish parsing
				ThreadPool.QueueUserWorkItem(new WaitCallback(_myParserClass.getIncomingData),stringArray);
				if (_createFile)
				{
					ThreadPool.QueueUserWorkItem(new WaitCallback(CreateFileThread),stringArray);
				}
				CurrentState = CapState.capturing;
			break;
			case CapState.capturing:
				DataTimer.Enabled = false;	//data coming in so reset the timer by turning it off first
				ThreadPool.QueueUserWorkItem(new WaitCallback(_myParserClass.getIncomingData),stringArray);
				if (_createFile)
				{
					ThreadPool.QueueUserWorkItem(new WaitCallback(CreateFileThread),stringArray);
				}
				DataTimer.Enabled = true;	// turn the timer back on therefor resetting the timeout to whatever the value is
			break;
		}
	}
	catch(Exception ex)
	{
		myLog.Log(string.Format("Error in DataAvail. Error: {0}",ex.Message));
		myLog.Log(string.Format("Stack Trace for DataAvail Error: {0}",ex.StackTrace));
		DataCaptureException ev = new DataCaptureException(ex.Message,ID);
		CaptureException(ev);
		MessageBox.Show(ex.Message);
	}
}
 
Ok I figured it out. The biggest thing to remember here is that you can't count on when a thread will execute on a lock if there are possibly mutlitple threads waiting for that piece of code.

But what I ended up doing was placing the data in a queue as soon as it comes in on my DataAvail event and then spinning of threads that read from the queue and by using Queue.SyncRoot to lock the usage of the Queue it keeps my Data in order...

Thanks all again for your help
 
Back
Top