【发布时间】:2017-12-08 10:04:16
【问题描述】:
我对以下 C# 代码的线程激活顺序感到困惑。它创建10个线程,随机启动它们,每个线程模拟执行一个耗时的工作10次,如果你检查调试输出,线程似乎不是随机提取的,请看下面的输出示例,注意线程#3 ,#5,#6总是捡起来,当#3 #5 #6完成后,#10 #2 #8总是捡起来,等等……(我知道设计不好,请关注现象)
我的电脑有 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);
}
}
}
}
}
The screenshot of debug output
--- 附加信息 ---
- 该程序根本不是并行程序,因为 10 个线程之间共享锁。
- 如果循环计数从 10 变为无限,则始终激活 3 个线程,其余 7 个线程无法获得激活机会,就像永远“死锁”一样。
【问题讨论】:
-
尝试在循环之前将
Random rng = new Random();添加到ThreadProc(),然后在循环中执行Thread.Sleep(400 + rng.Next(200));,看看是否会得到不同的结果。也许发生了某种锁定步骤。 -
没有订单。实际上,操作系统有意避免意外排序,这是针对锁车队的对策。后台is here.
-
最令人困惑的是,有10个线程,只能激活3个线程,在循环结束之前,线程调度器总是选择这3个线程,其余7个一直在等待。不应该每个线程都有相同的机会被激活吗?
标签: c# .net multithreading locking