在线程中的Thread.Join也阻塞子线程

时间:2012-04-03 15:57:19

标签: c# winforms multithreading

这可能是一个愚蠢的问题,如果这已经在其他地方得到了答案,那么如果有人能指出我,我会非常感激,因为我的搜索没有发现任何确定的东西。


简而言之,我的问题是,当我在子线程上的子线程中执行childThread.Join()时,标记为停止childThread的子线程似乎阻塞了主线程,所以一切都只是挂起。登记/> 因为使用Join而阻止用户界面本身并不是一个问题,因为childThread应该在被告知要退出之后不到一秒钟完成。
这种情况发生在我正在等待运行重复进程的线程退出之前,我可以运行另一个方法,该方法返回一些信息但不能与另一个进程同时运行。

My Winforms应用程序通过为硬件设置C API来集成一块USB硬件。

硬件API有一个方法可以启动一个无限期重复运行的进程,并使用新信息快速回调,然后我需要将这些信息传递给用户界面。
可以通过另一次调用硬件API取消此操作,硬件API设置硬件可以看到的标志,以便它知道退出 我用自己的C#代码包装了这个C API,在包装器中我必须在另一个线程中分离出启动进程调用,这样活动就不会阻塞UI。

以下是我正在做的大致编辑的重点。

public class DeviceWrapper
{
    Thread childThread = null;

    void DeviceWrapper 
    {
        //Set the callback to be used by the StartGettingInformation() process
        PInvokeMethods.SetGetInformationCallback(InformationAcquiredCallback);
    }

    public void StartProcess()
    {
        childThread = new Thread(new ThreadStart(GetInformationProcess))
        childThread.Start();
    }

    void GetInformationProcess()
    {
        PInvokeMethods.StartGettingInformation();
    }

    //This callback occurs inside the childThread
    void InformationAcquiredCallback(Status status, IntPtr information)
    {
        //This callback is triggered when anything happens in the 
        //StartGettingInformation() method, such as when the information 
        //is ready to be retrieved, or when the process has been cancelled.
        if(status == Status.InformationAcquired)
        {
            FireUpdateUIEvent();
        }
        //If the cancel flag has been set to true this will be hit.
        else if(status == Status.Cancelled) 
        {
            //Reset the cancel flag so the next operation works ok
            PInvokeMethods.SetCancelFlag(false); 

            childThread.Abort();
        }
    }

    //This method runs once, and can't run at the same time as GetInformationProcess
    public string GetSpecificInformation()
    {
        //This triggers InformationAcquiredCallback with a status of Cancelled
        StopProcess(); 

        if(childThread.IsAlive)
        {
            childThread.Join();
        }

        return PInvokeMethods.GetSpecificInformation();
    }

    public void StopProcess()
    {
        PInvokeMethods.SetCancelFlag(true);
    }
}

当我调用childThread.Join()时使用这段代码,整个应用程序会停止(我期望用户界面,这很好),而且childThread也似乎停止了,因为回调永远不会再次被击中。 / p>

但是,如果我改为使用以下代码:

public string GetSpecificInformation()
{
    //This triggers InformationAcquiredCallback with a status of Cancelled
    StopProcess(); 
    string s = "";

    ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
    {
        if(childThread.IsAlive)
        {
            childThread.Join();
        }
        s = PInvokeMethods.GetSpecificInformation();            
    }));

    return s;
}

然后一切都按预期命中,childThread完成并且一切都很好,除了很明显我的字符串在WaitCallback触发并分配给它之前返回为空。

那么,我是否只需要修改它并更改类,以便我使用QueueUserWorkItem和WaitCallback并触发事件来处理我的字符串返回?
在我的第一个方法中是否有一些愚蠢的行为导致childThread也被阻止了? 或者是否有我应该使用的另一种策略或类,记住它是.NET 3.5我在吗?

1 个答案:

答案 0 :(得分:5)

好吧,FireUpdateUIEvent();听起来像是一种可能发布发送到MsgQueue(Control.Invoke())的方法。当主线程在Join()中等待时,您就会遇到经典的死锁。

此外,childThread.Abort()不被视为安全。

  

那么,我是否只需要修改它并更改类,以便我使用QueueUserWorkItem和WaitCallback并触发事件来处理我的字符串返回?

我当然会重新设计它。它可能可以简化一点。