我写了这个小程序:
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(WriteX);
t.Start();
for (int i = 0; i < 1000; i++)
{
Console.Write("O");
}
}
private static void WriteX()
{
for (int i = 0; i < 1000; i++)
{
Console.Write(".");
}
}
}
我跑了大约五十次,控制台上的第一个字符总是“O”。这对我来说很奇怪,因为t
线程首先开始,然后主要继续。
对此有任何解释吗?
答案 0 :(得分:53)
这可能是因为Thread.Start首先导致调用它的线程状态发生变化,OS调度它以执行而 主线程已经运行且不需要这两个步骤。这可能是主线程中的语句首先执行而不是新创建的线程中的语句的原因。请记住,不保证线程执行的顺序。
1)Thread.Start方法使操作系统改变状态 ThreadState.Running的当前实例。
2)一旦线程处于ThreadState.Running状态,操作 系统可以安排它执行。线程开始执行 ThreadStart表示的方法的第一行
编辑在我看来,以图形形式表示这一点会使这更清晰易懂。我试图在下图中显示线程执行的顺序。
答案 1 :(得分:20)
你说:
&#34;对我来说这很奇怪,因为t线程首先开始然后主要继续。&#34;。
事实并非如此。 &#34;主要&#34;胎面已经开始了。执行t.Start();
时,操作系统会被告知t
处于运行状态。然后操作系统将为线程安排执行时间&#34;很快&#34;。除了OS被指示在线程t
启动之前停止执行此线程之外,这是其他内容。换句话说,当Start
返回时,无法保证线程已经开始执行。
答案 2 :(得分:13)
更多建议而不是答案:
(请注意,我认为您尝试实现的目标没有现实用途,因此我将您的问题视为思想实验/未详细解释的概念证明。)
如果你想要你的线程'&#34;比赛&#34;为了控制,不要让你的主线先行!创建一个线程有一些开销,你的主线程已经创建(因为它创建了你的另一个线程)。如果您正在为主线程和工作线程寻找大致相等的机会,则应等待在主线程中创建工作线程并等待主线程在后台线程中开始竞争。这可以通过synch objects获得。
在实践中,它看起来像这样:
你应该声明两个 ManualResetEvent ,它们对你的主线程和后台线程都是可见的,如下所示:
private static ManualResetEvent backgroundThreadReady = new ManualResetEvent(false);
private static ManualResetEvent startThreadRace = new ManualResetEvent(false);
然后在你的主线程中,你应该等待你的线程被初始化,如:
static void Main(string[] args)
{
Thread t = new Thread(WriteX);
t.Start();
backgroundThreadReady.WaitOne(); // wait for background thread to be ready
startThreadRace.Set(); // signal your background thread to start the race
for (int i = 0; i < 1000; i++)
{
Console.Write("O");
}
}
在你的主题中:
private static void WriteX()
{
backgroundThreadReady.Set(); // inform your main thread that this thread is ready for the race
startThreadRace.WaitOne(); // wait 'till the main thread starts the race
for (int i = 0; i < 1000; i++)
{
Console.Write(".");
}
}
请注意我可以使用其他可等待的同步对象(互斥锁,自动复位事件,甚至是关键部分锁定和一些黑客攻击,我只选择最简单,最快速的解决方案,可以轻松扩展) 强>
答案 3 :(得分:4)
它基本上需要时间来启动线程。您正在与第一个方法的其余部分同时运行线程代码。因此,考虑到启动线程然后到达写入“。”所需的时间。这有意义吗?
如果您的应用中有一种重置按钮可以再次启动所有内容(不退出),您可能会发现第一个字符是“。”因为线程已经存在。
答案 4 :(得分:4)
您的代码不确定。您的代码不包含任何线程原语,这些原语可以调度一个线程优先于另一个线程,或者一个线程等待另一个线程。
答案 5 :(得分:4)
主进程在调用线程后继续其下一个指令集,启动线程方法作为轻量进程需要一些时间。
答案 6 :(得分:0)
主线程在创建的线程之前完成的原因只有一个,那是因为启动线程需要时间。您可以使用线程加速程序的唯一时间是在同一时间运行2个任务。如果你想先做第二次循环,看看c#中的Parallel.For循环...这些将同时在for循环中运行每个循环(不是全部,而是你的PC可以处理多少循环) )