Multithreading 在另一个线程中处理异常会创建另一个线程
我最近看到了以下代码:Multithreading 在另一个线程中处理异常会创建另一个线程,multithreading,c#-4.0,thread-safety,Multithreading,C# 4.0,Thread Safety,我最近看到了以下代码: static List<Thread> list = new List<Thread>(); static void Main(string[] args) { var lines = File.ReadAllLines(args[0]); foreach (var line in lines) { StartThread(line); } Console.WriteLine("JOIN
static List<Thread> list = new List<Thread>();
static void Main(string[] args)
{
var lines = File.ReadAllLines(args[0]);
foreach (var line in lines)
{
StartThread(line);
}
Console.WriteLine("JOIN");
foreach (Thread thread in list)
{
thread.Join();
}
Console.WriteLine("END");
Console.ReadKey();
}
static void Upsert(object o)
{
var args = o.ToString().Split(',');
try
{
using (var con = new SqlConnection(Settings.Default.ConnString))
{
var cmd = new SqlCommand
{
Connection = con,
CommandText = "INSERT INTO Accounts VALUES(@p1, @p2, @p3, @p4, @p5)"
};
for (var index = 0; index < args.Length; index++)
{
cmd.Parameters.AddWithValue(@"@p" + (index + 1), args[index]);
}
try
{
con.Open();
cmd.ExecuteNonQuery();
Console.WriteLine("INSERTED");
}
catch (SqlException e)
{
switch (e.Number)
{
case 2627:
cmd.CommandText =
"UPDATE Accounts SET Name=@p2, Email=@p3, Active=@p4, Birthday=@p5 WHERE ID = @p1";
cmd.ExecuteNonQuery();
Console.WriteLine("UPDATED");
break;
case 1205:
StartThread(o); // On exception isn't some Thread handling should happen?
break;
}
}
}
}
}
private static void StartThread(object o)
{
// Is it correct to add another thread to the list again? when exception happens? What about the thread that was running
var t = new Thread(Upsert)
{
Priority = ThreadPriority.Highest,
IsBackground = true
};
list.Add(t);
t.Start(o);
Console.WriteLine("NEW THREAD STARTED");
}
静态列表=新列表();
静态void Main(字符串[]参数)
{
var lines=File.ReadAllLines(args[0]);
foreach(行中的var行)
{
开始线程(行);
}
Console.WriteLine(“加入”);
foreach(列表中的线程)
{
thread.Join();
}
控制台。写入线(“结束”);
Console.ReadKey();
}
静态空心向上插入(对象o)
{
var args=o.ToString().Split(',');
尝试
{
使用(var con=new SqlConnection(Settings.Default.ConnString))
{
var cmd=new SqlCommand
{
连接=con,
CommandText=“插入帐户值(@p1、@p2、@p3、@p4、@p5)”
};
对于(变量索引=0;索引
我对线程不是很在行,我想知道当错误1205可能发生时,代码会是什么样子,然后用相同的方法再次运行另一个线程,并再次添加到te线程列表中。如果前一个异常cougt线程已完成并中止,则不应该对其进行检查吗?然后将其从列表中删除并添加新的
你的贡献真的很有帮助
谢谢。你说得对,这段代码有几个问题
- 对
列表的访问不以任何方式同步
- 在错误1205之后,主线程连接和正在创建的新线程之间存在争用
SqlBulkCopy
一次性将所有记录放入临时登录区表中。最后,调用存储过程将临时登录区域中的记录转移到适当的生产表中。所有这些都可以在不使用任何工作线程的情况下完成,而且速度可能也会显著加快
更新:
如果使用CountdownEvent
,则可以轻松修复代码。完全丢弃线程列表,并实例化一个CountdownEvent
来执行等待,而不是在所有线程上调用Join
static CountdownEvent complete = new CountdownEvent(1);
static void Main(string[] args)
{
var lines = File.ReadAllLines(args[0]);
foreach (var line in lines)
{
StartThread(line);
}
Console.WriteLine("JOIN");
complete.Signal();
complete.Wait();
Console.WriteLine("END");
Console.ReadKey();
}
然后像这样更改StartThread
private static void StartThread(object o)
{
complete.AddCount();
var t = new Thread(
() =>
{
try
{
Upsert(o);
}
finally
{
complete.Signal();
}
});
t.Priority = ThreadPriority.Highest;
t.IsBackground = true;
t.Start();
Console.WriteLine("NEW THREAD STARTED");
}
因此,我要做的是用1个计数初始化condownEvent
,因为我希望将主线程视为工作线程。这将修复可能出现的任何微妙的争用条件,如果一个工作线程在主线程完成所有其他线程的旋转之前完成。每次启动一个新线程时,我调用AddCount
,当该线程完成时,我调用信号。当然,主线程通过调用Wait
来等待一切
如果我想稍微改变代码的结构,我可能会通过Task
使用任务,然后当出现错误1205时,我会创建一个子任务,并通过TaskCreationOptions.AttachedToParent
将其附加到父任务。但是,这需要一些更重要的更改,我希望将更改保持在最低限度。谢谢您的评论。但我想知道是否有人可以在客户端帮助当前的线程操作。比如说,你没有访问数据库的权限,无法访问你推荐的好地方的更改。你扔了一颗核弹,thanx伙计。You rock:)我第一次看到这段代码:对代码中许多错误的地方有很多评论