从控制台和WinForm比较的进程处理方式

3
下面的控制台应用程序可以正常运行——我很惊讶它没有出错。
class DelegateExperiments
{

    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    //open notepad when the console begins
    //create an event that fires and writes "Notepad closed" in the console
    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    //instance variables of the form
    private const string helloText = "hello world";
    private const string exitText = "you just closed notepad";
    private Process myProcess;
    //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<        


    static void Main(string[] args)
    {

        Console.WriteLine(helloText);

        DelegateExperiments myInstance;
        myInstance = new DelegateExperiments();
        myInstance.Foo();

        Console.Read();
    }

    void Foo()
    {

        myProcess = new Process();
        myProcess.StartInfo.FileName = @"notepad.exe";
        myProcess.Exited += MyProcessExited;
        myProcess.EnableRaisingEvents = true;
        //myProcess.SynchronizingObject = this;
        myProcess.Start();

    }

    private void MyProcessExited(Object source, EventArgs e)
    {
        Console.WriteLine(exitText);
    }


}

如果我尝试使用Winform来实现类似的功能,例如向表单上的标签写回消息,则需要更复杂的操作,并且需要使用以下代码才能正常工作:myProcess.SynchronizingObject = this;。为什么它们之间会有区别呢?

2个回答

6
Console 类有意编写成线程安全的。你可以从任何线程调用它。甚至会确保不会出现来自不同线程的“重叠”调用。Console.Write/WriteLine 是原子操作。这是因为 Console 设计用于与 shell 交互,而 shell 的一个主要目的是能够从多个进程中收集输入。实现这一点需要相当多的工作,但必须这样做才能真正地实现其目的。

GUI 对象(例如标签)并非设计时考虑到这一点。


即使Write/WriteLine不是原子操作,也要+1。甚至远远不是原子操作。原子操作只有汇编操作:Add、Sub、Mov、Jz、Cmp等…… - SimpleVar
2
如果你有一个写入行,打印出“hello”和另一个打印“world”,你将得到“hello world”或“world hello”。你不会得到“helworldlo”或类似的东西。因此,你可以说Console.Write是原子的。它并不是本质上的原子性,而是因为使用锁或其他类似机制来确保它的原子性。你可以让多个程序集操作成为原子操作。 - Servy
在这种情况下,他指的是线程方面。我说的是处理器方面。 - SimpleVar
@Servy,“线程安全”一词本质上包含“进程安全”一词。但无论如何,我们正在讨论不同类型的“原子性”,所以就这样吧。好答案 :) - SimpleVar
1
@YoryeNathan(很高兴你们亲吻并和好了:)) - whytheq
显示剩余2条评论

0

在WinForms中,所有对UI元素的访问都必须在专用的UI线程上进行。请参见1.2.1节这里

正如文档所说:

当Exited事件由可视化Windows Forms组件(例如Button)处理时,通过系统线程池访问该组件可能无法正常工作,或者可能导致异常。通过将SynchronizingObject设置为Windows Forms组件来避免这种情况,这会导致处理Exited事件的方法在创建组件的同一线程上调用。


问题是为什么GUI需要从单个线程中全部触摸。 - Servy
实际上更具体的是 - 为什么需要设置myProcess.SynchronizingObject - 我粘贴的引用解释了这会导致处理程序在与UI相同的线程上执行。你可以认为这个答案太具体了,那就随便吧。 - sinelaw
好的,答案太具体了,没有提供任何有意义的见解,说明为什么 GUI 应用程序需要一个 UI 线程,而控制台应用程序没有“控制台”线程。 - Servy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接