繁体   English   中英

C#多线程一些线程似乎无法运行

[英]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没有被击中( 2077920820779211 )。 我无法理解为什么会这样......在这两天花了两天后,我完全迷失了。

这是多线程环境中的典型问题吗? 我怎样才能更好地处理这个? 我必须确保每个项目只处理一次。

另外,我实现有时相同项目正在被处理多于一次(更2077920920779231 ),然而,我处理它在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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM