【问题标题】:A question about thread.Sleep() , thread.Join()关于 thread.Sleep() , thread.Join() 的问题
【发布时间】:2022-01-10 23:10:12
【问题描述】:

有如下代码,问题是: 哪些玩家会先被写入终端

我很容易理解 Start() 和 Join() 的功能,即立即启动线程。但是,我不确定首先将哪些玩家写入终端。我的理解是,可能是threadE、threadC、threadA,没找到正确答案。

如果有人有线索?谢谢。

class Player
{
    private readonly string tag;

    public Player(string name)
    {
        this.tag = name;
    }

    public void Run()
    {
        Thread.Sleep(100);
        Console.Write(tag + ",");
    }

    static void Main(string[] args)
    {
        Thread threadA = new Thread(new Player("A").Run);
        Thread threadB = new Thread(new Player("B").Run);
        Thread threadC = new Thread(new Player("C").Run);
        Thread threadD = new Thread(new Player("D").Run);
        Thread threadE = new Thread(new Player("E").Run);


        threadE.Start(); 
        threadC.Start();
        threadA.Start();
        threadC.Join();  
        threadB.Start();
        threadA.Join();
        threadD.Start();
        threadB.Join();
        threadD.Join();
        threadE.Join();
    }
}

【问题讨论】:

  • 所有可以肯定的说法是 B 肯定发生在 C 之后,而 D 肯定发生在 C 和 A 之后。其他一切都是实现定义的,并且可能会在每次运行时发生变化,具体取决于调度器正在做
  • 这是一场竞赛,你不能假设一个线程在没有同步的情况下在另一个线程之前完成。唯一的保证是 C 出现在 B 之前,D 出现在 A 之前,这要归功于 Join() 调用,仅此而已。
  • 任何时候你需要一个程序以特定的顺序执行某些事情,这表明这些事情可能都应该在同一个线程中完成。使用多线程的全部目的是让事情发生concurrently。但是,就其定义而言,并发性与事物以明确的、可预测的顺序发生的想法是不相容的。

标签: c# multithreading join sleep


【解决方案1】:

正如汉斯所说,这是一场比赛。关于执行顺序,我们只能说几件事。

不要让Sleep 欺骗您。它不能保证任何事情。就其本质而言,它并不十分准确,因此,同时启动 2 个Sleeps 很容易导致其中一个比另一个快 3 毫秒。

让我们分解代码。

//E, C and A start simultaneously.
//the order in which they complete is unpredictable.
threadE.Start(); 
threadC.Start();
threadA.Start();

//We wait on C here. Note that A and E might not be completed yet.
threadC.Join();  

//B starts after C completes. Possibly E and E are not finished yet.
//While unlikely (due to the sleep), this B can complete even before E and A completes.
//the only thing guaranteed is that B will start after C completes.
threadB.Start();

//Now we wait till A completes
//Most likely it's already done
threadA.Join();

//D will start here.
//Again, D might finish before B
threadD.Start();

//now we wait till everything is done.
threadB.Join();
threadD.Join();
threadE.Join();

所以,他很容易验证。注意:如果您自己运行此程序并稍微使用Sleep 的值,您会注意到该值越小(大约 2~3 毫秒),它的可预测性就越差。此外,CPU 负载可能会影响并行操作的结果。

请注意,并行性和线程并不像看起来那么简单。最后,您拥有有限数量的 CPU 和核心 - 这需要根据顺序和负载导致结果中的变化来处理导致的指令。

对于 WriteLine 的执行顺序,最终没有一个答案。

【讨论】:

  • 非常感谢大家,尤其是@Stefan!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-09
  • 1970-01-01
  • 2014-09-16
相关资源
最近更新 更多