ConcurrentQueue一个元素被两个线程占用

Ill*_*nia 1 c# multithreading interlocked interlocked-increment

我希望两个线程与一个队列一起工作。第一个线程应该每2秒调用一次,第二个线程-每3秒调用一次。这两个线程应同时启动。访问队列的第一个元素时出现问题。两个线程都采用索引为0的元素。有时,它与队列的其他元素一起发生,而不仅仅是第一个元素。我在控制台上有这样的输出:

  • 物品0被1处理:3:27:8
  • 项目0被2处理:3:27:8
  • 项目2由1处理:3:27:10
  • 项目3由2处理:3:27:11
  • 第1项处理的项目4:3:27:12

等等..

这是我使用的代码:

    ConcurrentQueue<int> sharedQueue = new ConcurrentQueue<int>();

    for (int i = 0; i < 10; i++)
    {
        sharedQueue.Enqueue(i);
    }


    int itemCount= 0;


    Task[] tasks = new Task[2];
    for (int i = 0; i < tasks.Length; i++)
    {
        // create the new task
        tasks[i] = new Task(() =>
        {
            while (sharedQueue.Count > 0)
            {
                // define a variable for the dequeue requests
                int queueElement;
                // take an item from the queue
                bool gotElement = sharedQueue.TryDequeue(out queueElement);
                // increment the count of items processed
                if (gotElement)
                {
                    DateTime dt = DateTime.Now;
                    Console.WriteLine("Item " + itemCount + "processed by " 
                        + Task.CurrentId + " Time: " + dt.Hour + ":" + dt.Minute + ":" + dt.Second);
                    Interlocked.Increment(ref itemCount);   
               if (Task.CurrentId == 1) 
                    Thread.Sleep(2000);
                else 
                    Thread.Sleep(3000);                       
                }

            }
        });
        // start the new task
        tasks[i].Start();


    }
    // wait for the tasks to complete
    Task.WaitAll(tasks);
    // report on the number of items processed
    Console.WriteLine("Items processed: {0}", itemCount);
    // wait for input before exiting
    Console.WriteLine("Press enter to finish");
    Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)

Bri*_*eon 5

替换以下行:

Console.WriteLine("Item " + itemCount + "processed by " ...);
Run Code Online (Sandbox Code Playgroud)

用这行:

Console.WriteLine("Item " + queueElement + "processed by " ...);
Run Code Online (Sandbox Code Playgroud)

您看到的问题很可能是由于任务Console.WriteLine几乎同时执行,并且两者都看到了相同的价值,itemCount因为它们以Interlocked.Increment尚未发生调用的方式交错。queueElement无论如何,打印出来可能更有意义,因为它更有意义。

  • +1。更重要的是,`itemCount`根本没有意义,因为线程A可以获取第一个项目,线程B获取第二个项目,但是随后线程B首先使`itemCount`递增。因此,尽管线程B实际上获得了项目2,但它将报告其获得了项目1。 (2认同)