4核PC上的C#程序中的线程激活顺序



我对以下C#代码的线程激活顺序感到困惑。它创建10个线程,随机启动它们,每个线程模拟以执行耗时的工作10次,如果您检查了调试输出,则该线程似乎不是不会随机拾取的,请参见下面的输出示例,请注意,请注意TREES#3,#5,#6总是被拾取,当#3#5#6完成时,#10#2#8总是被捡起等等...(我知道设计很糟糕,请专注于现象)

我的PC具有i7-7820HQ CPU,它具有4个内核,并且正在运行Windows 10。

有人可以解释为什么没有随机选择这些线程,并且似乎以某种方式分组。

非常感谢!

----调试输出----

线程#10获得了锁,并为任务#0工作线程#5获得了锁,并为任务#0工作线程#3获得了锁,并为任务#0工作线程#6获得了锁,并为任务#0工作线程#5获得了锁,并为任务1工作线程#3获取了锁,并为任务#1工作线程#6获取了锁,并为任务#1工作...线程#5获取了锁,并为任务#9工作线程#3获取了锁,并为任务#9工作线程#6获取了锁,并为任务#9工作...线程#8获得了锁,并为任务#0工作线程#2获取了锁,并为任务#0工作线程#8获得了锁,并为任务1工作线程#2获取了锁,并为任务#1工作线程#10获取了锁,并为任务#1工作...线程#8获取了锁,并为任务#9工作线程#2获取了锁,并正在为任务9工作线程#10获取了锁,并为任务#9工作...
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
    class Program
    {
        static Hashtable _sharedBetweenThreads = new Hashtable();
        static void Main(string[] args)
        {
            Random random = new Random(DateTime.Now.Second);
            var startOrders = new int[10];
            for (int i = 0; i < startOrders.Length; i++)
            {
                startOrders[i] = i;
            }
            //shuffle the array
            for (int i = startOrders.Length - 1; i >= 0; i--)
            {
                int j = random.Next(0, i);
                int temp = startOrders[i];
                startOrders[i] = startOrders[j];
                startOrders[j] = temp;
            }

            Thread[] threads = new Thread[startOrders.Length];
            for(int i = 0; i < startOrders.Length; i++)
            {
                threads[i] = new Thread(new ThreadStart(ThreadProc));
            }

            for (int i = 0; i < startOrders.Length; i++)
            {
                threads[startOrders[i]].Start();
            }
            Console.ReadLine();
        }
        static void ThreadProc()
        {
            // simulates there are 10 tasks needs to do.
            for (int i = 0; i < 10; i++)
            {
                lock (_sharedBetweenThreads.SyncRoot)
                {
                    Debug.Print(string.Format("Thread #{0} acquired the lock and is working for task #{1}", Thread.CurrentThread.ManagedThreadId, i));
                    // simulates a work.
                    Thread.Sleep(500);
                }
            }
        }
    }
}

调试输出的屏幕截图

---其他Infos ---

  • 该程序根本不是一个并行程序,因为在10个线程之间共享了锁。
  • 如果循环的计数从10更改为无限,则始终激活3个线程,其余的7个线程无法获得激活的机会,它们是永远的"僵局"。

我想您的困惑源于您正在使用.NET线程池的事实 - 例如托管线程池 - 但是您希望在系统级别上处理线程,这并不完全相同。内部线程池为您决定合适的线程。这与这个问题无关,哪个核心在哪个时刻运行哪个线程。

使用线程并不意味着您正在使用4个内核。

您必须并行使用:

class Program
{
    private static object _lock = new Object();
    static void Main(string[] args)
    {
        Random random = new Random(DateTime.Now.Second);
        int[] startOrders = new int[10];
        for (int i = 0; i < startOrders.Length; i++)
        {
            startOrders[i] = i;
        }
        //shuffle the array
        for (int i = startOrders.Length - 1; i >= 0; i--)
        {
            int j = random.Next(0, i);
            int temp = startOrders[i];
            startOrders[i] = startOrders[j];
            startOrders[j] = temp;
        }

        Thread[] threads = new Thread[startOrders.Length];
        for (int i = 0; i < startOrders.Length; i++)
        {
            threads[i] = new Thread(ThreadProc)
                             {
                                 Name = $"#{startOrders[i]}"
                             };
        }

        Parallel.ForEach(threads, thread => thread.Start());
        Console.ReadLine();
    }
    static void ThreadProc()
    {
        // simulates there are 10 tasks needs to do.
        for (int i = 0; i < 10; i++)
        {
            lock (_lock)
            {
                Debug.Print(
                    $"Thread {Thread.CurrentThread.Name} acquired the lock and is working for task #{i}");
                // simulates a work.
                Thread.Sleep(5);
            }
        }
    }
}

输出

Thread #6 acquired the lock and is working for task #0
Thread #4 acquired the lock and is working for task #0
Thread #8 acquired the lock and is working for task #0
Thread #6 acquired the lock and is working for task #1
Thread #5 acquired the lock and is working for task #0
Thread #3 acquired the lock and is working for task #0
Thread #6 acquired the lock and is working for task #2
Thread #7 acquired the lock and is working for task #0
Thread #9 acquired the lock and is working for task #0
Thread #6 acquired the lock and is working for task #3
Thread #4 acquired the lock and is working for task #1
Thread #8 acquired the lock and is working for task #1
Thread #0 acquired the lock and is working for task #0
Thread #5 acquired the lock and is working for task #1
Thread #3 acquired the lock and is working for task #1
Thread #7 acquired the lock and is working for task #1
Thread #9 acquired the lock and is working for task #1
Thread #2 acquired the lock and is working for task #0
Thread #1 acquired the lock and is working for task #0
Thread #0 acquired the lock and is working for task #1
Thread #6 acquired the lock and is working for task #4
Thread #4 acquired the lock and is working for task #2
Thread #8 acquired the lock and is working for task #2
Thread #3 acquired the lock and is working for task #2
Thread #7 acquired the lock and is working for task #2
Thread #5 acquired the lock and is working for task #2
Thread #9 acquired the lock and is working for task #2
Thread #2 acquired the lock and is working for task #1
Thread #0 acquired the lock and is working for task #2
Thread #1 acquired the lock and is working for task #1
Thread #6 acquired the lock and is working for task #5
Thread #4 acquired the lock and is working for task #3
Thread #8 acquired the lock and is working for task #3
Thread #5 acquired the lock and is working for task #3
Thread #3 acquired the lock and is working for task #3
Thread #7 acquired the lock and is working for task #3
Thread #6 acquired the lock and is working for task #6
Thread #4 acquired the lock and is working for task #4
Thread #8 acquired the lock and is working for task #4
Thread #5 acquired the lock and is working for task #4
Thread #3 acquired the lock and is working for task #4
Thread #7 acquired the lock and is working for task #4
Thread #6 acquired the lock and is working for task #7
Thread #4 acquired the lock and is working for task #5
Thread #8 acquired the lock and is working for task #5
Thread #5 acquired the lock and is working for task #5
Thread #3 acquired the lock and is working for task #5
Thread #7 acquired the lock and is working for task #5
Thread #9 acquired the lock and is working for task #3
Thread #6 acquired the lock and is working for task #8
Thread #4 acquired the lock and is working for task #6
Thread #5 acquired the lock and is working for task #6
Thread #8 acquired the lock and is working for task #6
Thread #4 acquired the lock and is working for task #7
Thread #3 acquired the lock and is working for task #6
Thread #6 acquired the lock and is working for task #9
Thread #7 acquired the lock and is working for task #6
The thread 0xfa0 has exited with code 0 (0x0).
Thread #5 acquired the lock and is working for task #7
Thread #8 acquired the lock and is working for task #7
Thread #9 acquired the lock and is working for task #4
Thread #4 acquired the lock and is working for task #8
Thread #3 acquired the lock and is working for task #7
Thread #0 acquired the lock and is working for task #3
Thread #7 acquired the lock and is working for task #7
Thread #5 acquired the lock and is working for task #8
Thread #8 acquired the lock and is working for task #8
Thread #4 acquired the lock and is working for task #9
Thread #3 acquired the lock and is working for task #8
The thread 0x329c has exited with code 0 (0x0).
Thread #9 acquired the lock and is working for task #5
Thread #7 acquired the lock and is working for task #8
Thread #5 acquired the lock and is working for task #9
The thread 0x3fcc has exited with code 0 (0x0).
Thread #8 acquired the lock and is working for task #9
The thread 0xe2c has exited with code 0 (0x0).
Thread #0 acquired the lock and is working for task #4
Thread #3 acquired the lock and is working for task #9
The thread 0x22ec has exited with code 0 (0x0).
Thread #2 acquired the lock and is working for task #2
Thread #7 acquired the lock and is working for task #9
The thread 0x2bfc has exited with code 0 (0x0).
Thread #9 acquired the lock and is working for task #6
Thread #1 acquired the lock and is working for task #2
Thread #0 acquired the lock and is working for task #5
Thread #2 acquired the lock and is working for task #3
Thread #2 acquired the lock and is working for task #4
Thread #9 acquired the lock and is working for task #7
Thread #2 acquired the lock and is working for task #5
Thread #1 acquired the lock and is working for task #3
Thread #0 acquired the lock and is working for task #6
Thread #0 acquired the lock and is working for task #7
Thread #9 acquired the lock and is working for task #8
Thread #2 acquired the lock and is working for task #6
Thread #1 acquired the lock and is working for task #4
Thread #1 acquired the lock and is working for task #5
Thread #0 acquired the lock and is working for task #8
Thread #9 acquired the lock and is working for task #9
The thread 0x1f44 has exited with code 0 (0x0).
Thread #1 acquired the lock and is working for task #6
Thread #2 acquired the lock and is working for task #7
Thread #2 acquired the lock and is working for task #8
Thread #0 acquired the lock and is working for task #9
The thread 0x1fc8 has exited with code 0 (0x0).
Thread #1 acquired the lock and is working for task #7
Thread #1 acquired the lock and is working for task #8
Thread #1 acquired the lock and is working for task #9
The thread 0x2ab0 has exited with code 0 (0x0).
Thread #2 acquired the lock and is working for task #9
The thread 0x2944 has exited with code 0 (0x0).
The thread 0x322c has exited with code 0 (0x0).
The thread 0x146c has exited with code 0 (0x0).
The thread 0x3dcc has exited with code 0 (0x0).
The thread 0x3928 has exited with code 0 (0x0).

我不确定,但是如果我使用thread.name,则thread.currentthread.managedthreadid似乎可以根据需要工作。可以是在线程启动时分配托管threadID,因此#12是执行中的最后一个是有意义的,因为它实际上是最后一个。

最新更新