I’m using the MySQL .Net libraries in an older C# application I’m rewriting. The Data Access Layer is rather obsolete but I’m trying to make the best of it. But now I ran into some really nasty threading issues.
I have a series of about 20 Select statements which are used to process a report. They take about 5 seconds to complete and I’m displaying a progress bar while the Select statements run. I’m launching the operations via a simple ThreadPool call:
[LATER EDIT: What happens is that I called the method below twice due to a bug in my UI – this doesn’t devalue the question though, merely explains why my threads were racing against each other.]
ThreadPool.QueueUserWorkItem(new WaitCallback(UpdateChart));
- Sometimes it works.
- Sometimes it crashes with a “possible IO stream race condition”.
- Sometimes it crashes with “connection should be open and valid”.
- Sometimes it crashes with “object reference not set…”.
All classes in my DAL are Static because I thought this is a good way of improving performance (not having to create new class instances for every little operation).
And all my DAL classes use the same “root” DAL class which builds Connections:
public static class MySQLConnectionBuilder
{
private static MySqlConnectionStringBuilder ConnectionStringBuilder = new MySqlConnectionStringBuilder();
//I'm initializing the ConnectionStringBuilder with my server password & address.
public static MySqlConnection GetConnection ()
{
return new MySqlConnection(ConnectionStringBuilder.ConnectionString);
}
}
All my DAL classes have functions which are similar to the crashing function. The crashing function looks like this:
public static STDS.UserPresence.user_presenceDataTable GetPresence (int aUserID, DateTime aStart, DateTime aEnd)
{
ta.Connection = MySQLConnectionBuilder.GetConnection();
ds = ta.GetPresenceForUserBetweenDates(aUserID, aStart, aEnd);
ta.Connection.Close();
return ds;
}
Ideas? Tips on improvement? Will the threading issue go away if I switch to a more object-oriented (instance-driven) DAL?
The line
Closes the connection last assigned to
ta.Connection– not always the connection created in the same thread. This may close a connection on which a query is currently running in another thread.If you want to quickly determine if this is what’s happening, mark the connection variable with a [ThreadStatic] attribute in the class
tapoints to:I wouldn’t use that approach for your final solution though, as it may cause the GC not to collect them.
A simple solution (for that problem, I can’t determine if your classes have other multithreading issues) is to add the connection as a parameter to each of your DAL methods, allowing you to remove the class global
Connection:Threading issues never simply go away – they require attention. If you are unsure about what’s happening, forget about the slight performance boost (if a query takes 5 seconds, any possible performance gain of using static classes would be below 1% anyway).