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

Nan*_*rin 1 c# multithreading winforms

这可能是一个愚蠢的问题,如果这已经在其他地方得到了解答,那么我真的很感激,如果有人可以指出我,因为我的搜索没有发现任何确定的.


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

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

硬件API有一个方法,它将启动一个无限期重复运行的进程,并使用新信息快速回调,然后我需要将这些信息传递给UI.
可以通过另一次调用硬件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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

Hen*_*man 5

嗯,FireUpdateUIEvent(); 听起来可能的方法发送到MsgQueue( Control.Invoke()).当主线程正在等待时,Join()你就会遇到经典的死锁.

另外,childThread.Abort()不被认为是安全的.

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

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