[英]C# multithreading some threads seems to not run
我有一个项目处理应用程序,我想并行处理多个项目。 但是,有时它似乎根本不处理一个项目,有时它不止一次处理。 我的代码如下
在计时器滴答声中,创建一个新线程,该线程从数据库中准备项目列表,然后锁定每个项目,以便在下一个循环中不会选择它。
SqlConnection connection = GetConnection();
string selectCommand = my_select_command_where_IsLocked_is_null;
List<Item> itemList = new List<Item>();
using(SqlDataAdapter adapter = new SqlDataAdapter(selectCommand, connection))
{
using(SqlCommandBuilder cbCommandBuilder = new SqlCommandBuilder(adapter))
{
DataTable dtItemStore = new DataTable();
adapter.Fill(dtItemStore);
int totalRows = dtItemStore.Rows.Count;
if(totalRows > 0)
{
adapter.UpdateCommand = cbCommandBuilder.GetUpdateCommand();
foreach(DataRow row in dtItemStore.Rows)
{
Item pickedItem = new Item();
pickedItem.Key = row["Key"].ToString();
// Set all Item properties
itemList.Add(pickedItem);
row["IsLocked"] = 1;
}
}
adapter.Update(dtItemStore);
}
}
然后它遍历列表,并为每个元素触发一个新线程来处理该项。
var keyList = "";
foreach(Item pickedItem in itemList)
{
Thread.Sleep(15); // Just to delay a bit
var newThread = new Thread(delegate() { ProcessItem(pickedItem); });
newThread.Start();
Logger.Log(" Spawn thread: " + pickedItem.Key + ", ThreadState: " + newThread.ThreadState);
keyList = keyList + pickedItem.Key;
}
Logger.Log("Keys picked: " + keyList);
项目处理器功能在循环结束时解锁项目。
function ProcessItem(Item pickedItem)
{
Logger.Log("Let's process !!! " + pickedItem.Key);
// Item processing code
UnlockItem(pickedItem); // unlock and write log
}
问题是,过了一段时间我意识到我的数据库中有太多锁定的项目,并且数量正在增加。 记录特定点我得到类似下面的内容
- Spawn thread: 20779205, ThreadState: Running
- Let's process !!! 20779205
- Spawn thread: 20779206, ThreadState: Running
- Let's process !!! 20779206
- Spawn thread: 20779207, ThreadState: Running
- Let's process !!! 20779207
- Spawn thread: 20779208, ThreadState: Running <---Not processed
- Let's process !!! 20779209 <---Duplicate
- Spawn thread: 20779209, ThreadState: Running
- Let's process !!! 20779209
- Spawn thread: 20779211, ThreadState: Running <---Not processed
- Let's process !!! 20779213
- Spawn thread: 20779213, ThreadState: Running
- Let's process !!! 20779228
- Spawn thread: 20779228, ThreadState: Running
- Let's process !!! 20779231
- Let's process !!! 20779231 <---Duplicate
- Spawn thread: 20779231, ThreadState: Running
- Spawn thread: 20779237, ThreadState: Running
- Keys picked: 20779205, 20779206, 20779207, 20779208, 20779209, 20779211, 20779213, 20779228, 20779231, 20779237,
- Let's process !!! 20779237
- STOP processing. Possible duplicate for 20779209
- STOP processing. Possible duplicate for 20779231
- Unlock Key: 20779209, Row count:1
- Unlock Key: 20779231, Row count:1
- Unlock Key: 20779209, Row count:1
- Unlock Key: 20779237, Row count:1
- Unlock Key: 20779228, Row count:1
- Unlock Key: 20779206, Row count:1
- Unlock Key: 20779207, Row count:1
- Unlock Key: 20779205, Row count:1
- Unlock Key: 20779231, Row count:1
在这里,我可以看到,有时ProcessItem
没有被击中( 20779208
, 20779211
)。 我无法理解为什么会这样......在这两天花了两天后,我完全迷失了。
这是多线程环境中的典型问题吗? 我怎样才能更好地处理这个? 我必须确保每个项目只处理一次。
另外,我实现有时相同项目正在被处理多于一次(更20779209
, 20779231
),然而,我处理它在ProcessItem
功能,以避免重复。 这两种情况之间是否存在联系?
我究竟做错了什么?
从输出线选择Keys picked: 20779205, 20779206, 20779207, 20779208, 20779209, 20779211, 20779213, 20779228, 20779231, 20779237
我会得出结论,所有项目都被击中(每次一次)
可能你应该修改你的代码:
var keyList = "";
foreach(Item pickedItem in itemList)
{
Thread.Sleep(15); // Just to delay a bit
Item tmpItem = pickedItem; -- the same variable should not be accessed by many threads
var newThread = new Thread(delegate() { ProcessItem(tmpItem); });
newThread.Start();
Logger.Log(" Spawn thread: " + pickedItem.Key + ", ThreadState: " + newThread.ThreadState);
keyList = keyList + pickedItem.Key;
}
Logger.Log("Keys picked: " + keyList);
您的日志显示在delegate() { ProcessItem(pickedItem); }
之前, foreach
循环将pickedItem
分配给下一个值delegate() { ProcessItem(pickedItem); }
delegate() { ProcessItem(pickedItem); }
执行。
您应该使用ParametrizedStart或在foreach
循环和ProcessItem
函数之间添加同步系统。
你真的需要'手动'生成线程吗? 将此任务留给框架:
itemList.AsParallel().ForAll((item) =>
{
Logger.Log("Processing item ...");
ProcessItem(item);
});
现在您要做的就是确保ProcessItem
方法是线程安全的。
ForAll
将阻止当前线程,直到对集合中的每个项目的操作完成为止。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.