3

有人可以告诉我以下代码有什么问题吗?理想情况下,它应该首先启动一个线程,然后等待设置事件。相反,它不会启动线程,只会卡在 WaitOne() 上。

我很想知道线程发生了什么,为什么?

class Program
{   
    static void Main(string[] args)
    {
        Testing t = Testing.Instance;
        Console.Read();
    }
}


class Testing
{
    private static AutoResetEvent evt = new AutoResetEvent(false);
    public static Testing Instance = new Testing();

    private Testing()
    {
        Create();
        evt.WaitOne();
        Console.WriteLine("out");
    }

    private void Create()
    {
        Console.WriteLine("Starting thread");
        new Thread(Print).Start();
    }

    private void Print()
    {
        Console.WriteLine("started");
        evt.Set();
    }
}

编辑: 到目前为止,@BrokenGlass 提供的描述是有道理的。但是将代码更改为以下代码允许另一个线程可以访问实例方法而无需完成构造函数。(@NicoSchertler 建议)。

private static Testing _Instance;

public static Testing Instance
{
get
{
    if (_Instance == null)
        _Instance = new Testing();
    return _Instance;
}
}
4

3 回答 3

5

我怀疑这种行为的根本原因是生成的线程在构造函数完成执行之前无法访问该Print方法 - 但构造函数永远不会完成执行,因为它正在等待仅从该Print方法触发的信号。

evt.WaitOne() 用长调用替换Thread.Sleep()确认相同的行为 - 构造函数必须在对象的任何实例方法可以从另一个线程执行之前完成运行。

于 2012-05-24T17:28:14.237 回答
3

问题是第二个线程创建得太早了。我不知道为什么,但是在主程序启动之前启动时,它不会执行。

您应该在其原始版本中使用单例模式。这将起作用。

private static Testing _Instance;

public static Testing Instance
{
    get
    {
        if (_Instance == null)
            _Instance = new Testing();
        return _Instance;
    }
}

此外,您不应将 evt 变量设为静态。在大多数情况下,实例变量应该是单例类的唯一静态成员。

于 2012-05-24T17:41:15.587 回答
0

我的猜测是静态字段初始化的相对时间问题。evt尝试在构造函数中初始化Testing

private static AutoResetEvent evt;
public static Testing Instance = new Testing();

private Testing()
{
    evt = new AutoResetEvent(false);
    Create();
    evt.WaitOne();
    Console.WriteLine("out");
}

我应该注意到这实际上只是一个猜测——我原以为这段代码可以正常工作。

于 2012-05-24T17:30:17.420 回答