【问题标题】:Will all the worker threads get generated at once?会同时生成所有工作线程吗?
【发布时间】:2017-05-16 05:06:20
【问题描述】:

有没有人可以解释一下这段代码的流程? 我想知道主线程是如何生成工作线程的,我知道的是:

一旦主线程调用 .start 方法,它就会创建一个新线程。 但是我对在 main 中循环多个线程时行为如何变化感到困惑。

static void Main()
{
Thread[] tr = new Thread[10];
for (int i = 0; i < 10; i++)
{

    tr[i] = new Thread(new ThreadStart(count));
    tr[i].Start();

}

static private void count()
{

    for (int i = 0; i < 10; ++i)
    {
        lock (theLock)
        {
            Console.WriteLine("Count {0} Thread{1}",
            counter++, Thread.CurrentThread.GetHashCode());

        }
    }

是否有调试和跟踪多线程程序的好方法。谷歌搜索后,我发现跟踪线程窗口处于调试状态,但即使在为线程提供自定义名称之后,我也找不到它有用。 我只是无法理解流程,线程如何启动,它们如何一起工作等等,因为断点在多线程应用程序中似乎没有影响。 (至少在我的情况下。)

【问题讨论】:

  • 线程将在“调用 Start 后不久的某个时间点”开始执行。然而,由于很少工作在每个线程内完成,所有线程不可能同时运行(即第一个线程可能在后面的线程创建之前完成)。在带有随机值的循环内使用Thread.Sleep 可以更好地查看线程交错。
  • 视情况而定。你不能肯定地知道这一点。为什么您需要知道所有线程是否“同时”启动。
  • 我只是想知道它们是如何工作的,这样我就可以实现我从前几天一直在尝试的逻辑。
  • @Eqra 每个人都想说明的是,当您编写多线程代码时,您必须编写逻辑,以便您的代码不关心线程的顺序开始。同样Thread.CurrentThread.GetHashCode()Thread.CurrentThread.ManagedThreadId 是一样的,但是第二个版本让你想要获取的信息更加明显。
  • @ScottChamberlain,先生,我想要这个输出 1 由 Thread 打印:4551 [ThreadID] 2 由 Thread 打印:4552 3 由 Thread 打印:4553 4 由 Thread 打印:4554 5 由 Thread 打印:4555 6由 Thread 打印:4556 7 由 Thread 打印:4557 8 由 Thread 打印:4558 9 由 Thread 打印:4559 10 由 Thread 打印:4560 11 由 Thread 打印:4551 [与 1 中再次出现相同的线程 ID] 12 由 Thread 打印: 4552 这就是为什么我要跟踪线程以及它们生成的时间点以获得所需的顺序。 :( 对不起,如果我要求太多。

标签: c# multithreading thread-safety


【解决方案1】:

我希望这个输出 1 由 Thread 打印:4551 [ThreadID] 2 由 Thread 打印 线程:4552 3 由线程打印:4553 4 由线程打印:4554 5 线程打印:4555 6 线程打印:4556 7 打印 线程:4557 8 由线程打印:4558 9 由线程打印:4559 10 由线程打印:4560 11 由线程打印:4551 [相同线程 ID 再次出现,如 1] 12 由 Thread 打印:4552

我将尝试描述您的代码在与线程子系统交互时所做的事情。我提供的细节来自我在大学操作系统设计课程中的记忆,因此主机操作系统和/或 CLR 内部的实际实现可能与我描述的有所不同。

static void Main()
{
Thread[] tr = new Thread[10];
for (int i = 0; i < 10; i++)
{

    tr[i] = new Thread(new ThreadStart(count));

    // The following line puts the thread in a "runnable" thread list that is
    // managed by the OS scheduler. The scheduler will allow threads to run by 
    // considering many factors, such as how many processes are running on 
    // the system, how much time a runnable thread has been waiting, the process
    // priority, the thread's priority, etc.  This means you have little control 
    // on the order of execution, The only certain fact is that your thread will
    // run, at some point in the near future.
    tr[i].Start();  

    // At this point you are exiting your main function, so the program should
    // end, however, since you didn't flag your threads as BackgroundThreads,
    // the program will keep running until every thread finishes.
}


static private void count()
{
   // The following loop is very short, and it is probable that the thread
   // might finish before the scheduler allows another thread to run
   // Like user2864740 suggested, increasing the amount of iterations will 
   // increase the chance that you experience interleaved execution between
   // multiple threads

    for (int i = 0; i < 10; ++i)
    {
        // Acquire a mutually-exclusive lock on theLock. Assuming that
        // theLock has been declared static, then only a single thread will be
        // allowed to execute the code guarded by the lock.    
        // Any running thread that tries to acquire the lock that is
        // being held by a different thread will BLOCK. In this case, the 
        // blocking operation will do the following:
        //    1. Register the thread that is about to be blocked in the
        //       lock's wait list (this is managed by a specialized class
        //       known as the Monitor)
        //    2. Remove the thread that is about to be blocked from the scheduler's
        //       runnable list. This way the scheduler won't try to yield
        //       the CPU to a thread that is waiting for a lock to be
        //       released.  This saves CPU cycles.
        //    3. Yield execution (allow other threads to run)
        lock (theLock)
        {
            // Only a single thread can run the following code
            Console.WriteLine("Count {0} Thread{1}",
            counter++, Thread.CurrentThread.GetHashCode());

        }
        // At this point the lock is released.  The Monitor class will inspect
        // the released lock's wait list. If any threads were waiting for the
        // lock, one of them will be selected and returned to the scheduler's
        // runnable list, where eventually it will be given the chance to run
        // and contend for the lock. Again, many factors may be evaluated 
        // when selecting which blocked thread to return to the runnable  
        // list, so we can't make any guarantees on the order the threads
        // are unblocked
    }
}

希望事情更清楚。 这里重要的是要承认,您几乎无法控制各个线程如何安排执行,因此无法(没有大量同步代码)复制您期望的输出。 ,您可以更改线程的优先级以提示调度程序某个线程必须优先于其他线程。然而,这需要非常小心地完成,因为它可能会导致一个被称为优先级反转的令人讨厌的问题。除非您确切知道自己在做什么,否则通常最好不要更改线程的优先级。

【讨论】:

  • 感谢您考虑并抽出时间使其易于理解_
  • 不客气,我看到您设法获得了您期望的交错序列,请随时将您自己的答案标记为正确的。 =)
  • 我现在做不到,谢谢下次_
【解决方案2】:

经过不断的尝试,我终于完成了我的任务要求。代码如下:

using System;
using System.Threading;
public class EntryPoint
{
    static private int counter = 0;
    static private object theLock = new Object();
    static object obj = new object();
    static private void count()
    {
        {
                for (int i = 0; i < 10; i++)
            {
                lock (theLock)
                {
                    Console.WriteLine("Count {0} Thread{1}",
                    counter++, Thread.CurrentThread.GetHashCode());
                     if (counter>=10) 
                    Monitor.Pulse(theLock);
                    Monitor.Wait(theLock);  }  }}
    }
    static void Main()
    {
        Thread[] tr = new Thread[10];
        for (int i = 0; i < 10; i++)
        {
            tr[i] = new Thread(new ThreadStart(count));
            tr[i].Start();
        }

    }
} 

监视器按顺序维护一个就绪队列,因此我实现了我想要的:

干杯!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多