nga*_*nju 13 .net c# multithreading
好吧,这看起来像.NET中的一个主要基本错误:
考虑以下简单程序,它故意尝试连接到不存在的数据库:
class Program
{
static void Main(string[] args)
{
Thread threadOne = new Thread(GetConnectionOne);
Thread threadTwo = new Thread(GetConnectionTwo);
threadOne.Start();
threadTwo.Start();
}
static void GetConnectionOne()
{
try
{
using (SqlConnection conn = new SqlConnection("Data Source=.\\wfea;Initial Catalog=zc;Persist Security Info=True;Trusted_Connection=yes;"))
{
conn.Open();
}
} catch (Exception e)
{
File.AppendAllText("ConnectionOneError.txt", e.Message + "\n" + e.StackTrace + "\n");
}
}
static void GetConnectionTwo()
{
try
{
using (SqlConnection conn = new SqlConnection("Data Source=.\\wfea;Initial Catalog=zc;Persist Security Info=True;Trusted_Connection=yes;"))
{
conn.Open();
}
}
catch (Exception e)
{
File.AppendAllText("ConnectionTwoError.txt", e.Message + "\n" + e.StackTrace + "\n");
}
}
}
Run Code Online (Sandbox Code Playgroud)
运行此程序并在catch块上设置断点.DBConnection对象将尝试连接15秒(在两个线程上),然后它将引发错误.检查异常的堆栈跟踪,堆栈跟踪将混合两个调用堆栈,如下所示:
at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject)
at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject)
at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
at System.Data.SqlClient.SqlConnection.Open()
at ZoCom2Test.Program.GetConnectionOne() in C:\src\trunk\ZTest\Program.cs:line 38
at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
at System.Data.SqlClient.SqlConnection.Open()
at ZoCom2Test.Program.GetConnectionTwo() in C:\src\trunk\ZTest\Program.cs:line 54
Run Code Online (Sandbox Code Playgroud)
您可能需要多次尝试才能实现此目的,但我现在正在我的机器上实现这一点.这怎么可能?这在VM级别应该是完全不可能的.看起来DBConnection.Open()函数同时在两个线程上抛出相同的异常,或类似的东西.
试试这个,看看会发生什么:
class ThreadingBug
{
private const string CONNECTION_STRING =
"Data Source=.\\wfea;Initial Catalog=catalog;Persist Security Info=True;Trusted_Connection=yes;";
static void Main(string[] args)
{
try
{
Thread threadOne = new Thread(GetConnectionOne);
Thread threadTwo = new Thread(GetConnectionTwo);
threadOne.Start();
threadTwo.Start();
threadOne.Join(2000);
threadTwo.Join(2000);
}
catch (Exception e)
{
File.AppendAllText("Main.txt", e.ToString());
}
}
static void GetConnectionOne()
{
try
{
using (SqlConnection conn = new SqlConnection(CONNECTION_STRING))
{
conn.Open();
}
}
catch (Exception e)
{
File.AppendAllText("GetConnectionOne.txt", e.ToString());
}
}
static void GetConnectionTwo()
{
try
{
using (SqlConnection conn = new SqlConnection(CONNECTION_STRING))
{
conn.Open();
}
}
catch (Exception e)
{
File.AppendAllText("GetConnectionTwo.txt", e.ToString());
}
}
}
Run Code Online (Sandbox Code Playgroud)
我相信这里有一个错误,虽然它既不是主要的,也不是根本的.在努力缩小范围之后(以及执行诸如删除一个线程之类的操作)之后,看起来Exception两个线程上的连接池实现抛出了类的相同实例(感谢Gregory发现这个).这有时会显示为损坏的("混合")堆栈跟踪,有时简单地表示两个线程上的堆栈跟踪相同,即使两个线程之间的代码完全不同.
注释掉其中一个Thread.Start调用会显示完全不同的堆栈跟踪,这表明奇数部分位于连接池实现中 - 奇数堆栈跟踪由连接池分发,因为两个线程都使用相同的连接字符串和凭据.
我已经在https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=522506上提交了Connect问题.每个人都可以自由地投票决定你觉得它有多重要(或不重要),你是否可以重现它,或者你是否有一个解决方法.这将有助于Microsoft确定修复程序的优先级.
更新: Connect问题已更新.微软承认这是一个错误,并计划在未来的版本中修复它.
感谢nganju,Gregory和其他所有参与解决此问题的人.这确实是一个错误,它将被修复,这是因为我们.