【问题标题】:Strange behavior in Thread线程中的奇怪行为
【发布时间】:2019-11-08 14:21:22
【问题描述】:

我正在使用 Linq 在循环中创建新线程并启动它们,然后我在以下循环中加入线程。但是,第一个循环引发了一个异常,我什至在加入线程之前就对此感到非常困惑。即使 indexOfHeaders 只有 3 个元素(索引为 0、1、2),我也得到一个索引超出范围异常和 i=3。但更奇怪的是,当我在调试器中中断异常时,即使所有其他局部变量都是可见的,我也看不到 int numberOfThreads 值。这是因为我错误地使用了 linq 或三元运算符吗?当我在调试器中缓慢地单步执行代码时,这些都无法重现。

private static void DecodeFileData(byte[] dataBuffer, UInt64 header, UInt64 trailer)
{
    byte[] headerBytesReceive = BitConverter.GetBytes(header);
    byte[] trailerBytesReceive = BitConverter.GetBytes(trailer);
    IEnumerable<int> indexOfHeaders = StartingIndex(dataBuffer, headerBytesReceive); //int indexOfHeader = Array.IndexOf(HundredKBBuffer, headerBytesReceive);
    // spawn up to 10 threads that look at the byte array for the right data
    SerialTest.DataFileWriter fileWriter = new SerialTest.DataFileWriter();
    int numberOfThreads = indexOfHeaders.Count() < 10 ? indexOfHeaders.Count() : 10;
    List<Thread> threadList = new List<Thread>();
    for (int i = 0; i < numberOfThreads; i++)
    {
        Thread decodeThread = new Thread(() => DecodeDataAsync(dataBuffer, headerBytesReceive, trailerBytesReceive, indexOfHeaders.ElementAt(i), fileWriter));
        threadList.Add(decodeThread);
        decodeThread.Start();
    }
    for (int i = 0; i < threadList.Count; i++)
        threadList.ElementAt(i).Join();
}

public static void DecodeDataAsync(byte[] dataBuffer, byte[] headerBytesReceive, byte[] trailerBytesReceive, int indexOfHeader, SerialTest.DataFileWriter fileWriter)
{ //lots of file writing and stuff that is irrelevent

DecodeFileData 从另一个方法同步调用。 从我发布的代码中可以看出,DecodeDataAsync 是异步的。

【问题讨论】:

  • DecodeDataAsync 不会因为你把 Async 放在最后就变成异步的。
  • 我明白了。也许我应该叫它别的名字,我只是为了提醒自己以异步方式调用它。这不是常见的做法吗?
  • 请注意,在 LINQ 表达式中使用循环变量将使用我在执行此表达式时所拥有的值。为避免这种情况,请将 i 分配给本地变量并使用它。
  • @Goku - 当i 等于3 时,它永远不会运行循环体。这并没有改变那个变量被设置为3这一事实,并且它是正在使用的那个变量的值。

标签: c# multithreading linq .net-core thread-safety


【解决方案1】:

你需要注意的两件事:

首先,您正在传递共享状态:

byte[] dataBuffer, byte[] headerBytesReceive, byte[] trailerBytesReceive, int indexOfHeader, SerialTest.DataFileWriter fileWriter

其次,变量i 不是线程本地的。

DecodeDataAsync(dataBuffer, headerBytesReceive, trailerBytesReceive, indexOfHeaders.ElementAt(i), fileWriter));

创建一个 Wrapper 函数,将其复制到一个局部变量中并传递给线程。

【讨论】:

  • 您能否写一个简短的示例说明“将其复制到线程的局部变量中”的含义,以便我能理解您的意思。您不必使用我的代码,只是一些示例
  • @Goku - 取决于您的要求。像这样的东西:void AddThreads(int i) { int idx = i; Thread decodeThread = new Thread(() =&gt; { Fun(idx) }); }
猜你喜欢
  • 2018-03-06
  • 1970-01-01
  • 2015-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-07
  • 2018-09-30
相关资源
最近更新 更多