为什么主线程的输出在C#中首先出现?
我写了这个小程序:
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
线程首先启动,然后主线继续。
这有什么解释吗?
这可能是因为Thread.Start首先引起了被调用的线程状态的改变,OS调度它来执行, 而 主线程已经运行,并不需要这两个步骤 。 这可能是主线程中的语句首先执行的原因,而不是新创build的线程中的语句。 请记住,线程执行的顺序不能保证。
Thread.Start方法
1)Thread.Start方法导致操作系统将当前实例的状态更改为ThreadState.Running。
2)一旦一个线程处于ThreadState.Running状态,操作系统可以调度它执行。 线程开始在ThreadStart表示的方法的第一行执行
编辑在我看来,以graphicsforms表示这将使这更清晰和可以理解。 我试图在下面的图中显示线程执行的顺序。
你说:
“对我来说这很奇怪,因为T线首先开始,然后主线继续。”
这不是真的。 “主要”步伐已经在运行。 当t.Start();
被执行,OS被告知t
处于运行状态。 然后操作系统将会“很快”为线程安排执行时间。 这是比操作系统被指示停止执行此线程,直到线程t
开始。 换句话说,当Start
返回时,不能保证线程已经开始执行。
更多的build议,而不是一个答案 :
(请注意,我没有看到你想要实现的东西,所以我把你的问题当成一个思想实验/一个没有详细解释的概念certificate。)
如果你想要你的线程“比赛”控制,不要让你的主线开始! 创build一个线程有一些开销,你的主线程已经被创build(因为它创build了你的其他线程)。 如果您正在为主线程和辅助线程寻找大致相等的机会,则应等待在主线程中创build工作线程,并等待主线程在后台线程中开始比赛。 这可以通过同步对象来实现 。
实际上它看起来像这样:
您应该声明两个对于主线程和后台线程均可见的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("."); } }
请注意,我可以使用其他等待同步对象(互斥,autoreset事件,甚至是一些黑客的关键部分锁,我只是select最简单,最快的解决scheme,可以轻松扩展)。
你的代码是不确定的。 您的代码不包含任何线程原语,这些线程原语可以调度一个线程优先于另一个线程或一个线程等待另一个线程。
主进程在调用线程之后继续其下一个指令集,启动线程方法需要花时间。
基本上需要时间来启动线程。 您正在运行线程代码与第一个方法的其余部分同时运行。 所以考虑到启动线程所需的时间,然后到达写入“。”的时间点。 那有意义吗?
如果您的应用程序中有一种重置button来重新开始一切(不退出),则可能会发现第一个字符是“。”。 因为线程已经存在。
主线程在创build线程之前完成的唯一原因是因为启动线程需要时间。 唯一一次使用线程来加速程序的时候是两个任务可以同时运行。 如果你想先完成第二个循环,看一看在C#中的Parallel.For循环…这些将同时在for循环中运行每个循环(不是所有的循环都可以像PC一样处理)