In a project, I discovered a peculiar behavior then connecting to a MySql instance using threads from a ThreadPool; the application froze and it looks like it is due to a deadlock inside MySqlConnection.Open
. This does not happen when I manually create the Thread and run the Start method.
All the threads are in the MySqlConnection.Open
method, and stays there. They don't seem to get any further to print out some log messsages - no log messages are ever produced for me running TestTask
.
On the other hand, running TestThreads
works, then then I get the log message I expect:
I would like to understand why ThreadPool fails when creating manual threads works? Why is MySqlConnection deadlocked in one case, but not the other?
Please note that since we are testing against the same MySql server, it is not a MySql configuration issue.
I also dont see how it can be ThreadPool starvation; we set the MinThread to 200. Also, since I never get a single Console.WriteLine in the TestTask
case, there must surely be something else?
CodePudding user response:
MySql.Data has some poorly-written async code inside it (besides the problem that none of the Async
methods are actually async).
For example, this code starts async work using a Task
, then calls Task.Wait
: https://github.com/mysql/mysql-connector-net/blob/4306c8484ec74b3ee1c349847f66acabbce6d63c/MySQL.Data/src/common/StreamCreator.cs#L98-L100
This is "sync-over-async", which is a well-known cause of deadlocks. The problem is most likely that the threadpool is blocked with your user code, so the work required to complete TcpClient.ConnectAsync
can't be queued, so none of the Task
s can complete, so no code can make forward progress.
You can work around that by forcing the threadpool to have more threads:
ThreadPool.SetMinThreads(500, 500);
// do NOT call ThreadPool.SetMaxThreads
You can also switch to MySqlConnector, which implements threading code properly, and doesn't need the SetMinThreads
workaround in order to run. I've added an example of what using MySqlConnector's async methods would be like.