Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Join拒绝承认子线程在;IsAlive“;属性是假的。C#_C#_Multithreading_Join - Fatal编程技术网

Join拒绝承认子线程在;IsAlive“;属性是假的。C#

Join拒绝承认子线程在;IsAlive“;属性是假的。C#,c#,multithreading,join,C#,Multithreading,Join,简而言之:我从我的表单中启动一个线程,然后稍后在它上使用Join方法。它终止了,但我的应用程序在加入时被卡住了,并且拒绝承认它已经完成了加入。什么会导致这种情况发生?我的线程从窗体上的按钮启动,并尝试从同一窗体上的第二个按钮加入 更多信息: 我有一个应用程序,它使用线程来完成通信和数字运算。假设主窗体是父线程,第一个子线程是Child1。启动Child1后,会与外部设备建立一些通信,并启动自己的两个子线程(Child2和Child3)来处理传入数据 当用户决定应用程序停止处理传入数据时,我需要C

简而言之:我从我的表单中启动一个线程,然后稍后在它上使用Join方法。它终止了,但我的应用程序在加入时被卡住了,并且拒绝承认它已经完成了加入。什么会导致这种情况发生?我的线程从窗体上的按钮启动,并尝试从同一窗体上的第二个按钮加入

更多信息: 我有一个应用程序,它使用线程来完成通信和数字运算。假设主窗体是父线程,第一个子线程是Child1。启动Child1后,会与外部设备建立一些通信,并启动自己的两个子线程(Child2和Child3)来处理传入数据

当用户决定应用程序停止处理传入数据时,我需要Child1终止(因此,如果需要,可以在恢复之前更改com设置)。我设置了一个停止事件,Child1退出它的执行循环,它做的第一件事是通知Child2和Child3不再需要它们(通过另一个停止事件),Child2和Child3通过Child1中的Join方法等待。这个很好用

不起作用的是,表单在设置停止事件(该事件提示Child1退出其运行循环并终止)后,还对Child1使用Join方法,但是,此联接将无限期地等待

逐步通过:当我逐步通过我的应用程序时,我注意到在使用Join之前,IsAlive属性为true。在我点击Child1.Join()之后,我无法再从线程中获取任何信息,因为它处于“JoinWaitSleep”状态。但是,如果我运行while循环,使窗体线程在Child1.IsAlive为true时休眠,则效果很好。我的第二个按钮是否是无法将Child1连接到它的线程的一部分


public void Run()
{   //Known as Child1
    //code to setup coms is here

    //Launch Builder threads
    InsertBackgroundMonitor("Launching Collector Threads");
    RunBuilders = true;

    //Known as Child2 and Child3
    BuildThread1 = new Thread(new ThreadStart(Cam1Builder));
    BuildThread2 = new Thread(new ThreadStart(Cam2Builder));
    BuildThread1.Start();
    BuildThread2.Start();

    while (!StopEventHandle.WaitOne(0, true))
    {
    //// Code that waits for coms and tosses data into lists
    }

    RunBuilders = false;

    //Wait for threads to terminate
    BuildThread1.Join();
    BuildThread2.Join();
}

private void RunButton_Click(object sender, System.EventArgs e)
{
    //Button for running the control thread
    ControlThread = new Thread(new ThreadStart(Run));
    ControlThread.Start();
}

private void StopButton_Click(object sender, System.EventArgs e)
{
    if (btnStop.Enabled)
    {   //Button for stopping the control thread
        StopEventHandle.Set();

        if (ControlThread != null)
        {
            while (ControlThread.IsAlive)
            {
                Thread.Sleep(100);
            }
            //somehow Join did not work
            //ControlThread.Join();
        }

        //Update buttons
        btnStart.Enabled = true;
        btnStop.Enabled = false;               
    }
}

由于我没有看到
Cam1Builder
Cam2Builder
方法的代码,因此我只能猜测可能导致这种情况的问题。1立即跳出来的可能性有:

  • 调用
    Join
    会阻止调用线程的执行。如果这是从UI线程完成的,那么它会停止消息泵。如果工作线程试图将消息发布到UI线程(例如通过
    Control.Invoke
    ),则两个线程都将死锁
  • 如果
    RunBuilders
    未标记为
    volatile
    或未在
    lock
    内访问,则其他线程无法在任何给定时间点预测其值
通常,不建议从UI线程调用
Join
。UI线程的特殊之处在于,它们运行的是一个不确定的循环,即调度和处理windows消息。这个循环是通过调用
应用程序启动的。运行你应该在代码中看到的
。如果通过调用
Join
或其他阻止方法阻止UI线程,则它无法处理排队的消息。您可能正在使用
Control.Invoke
从一个工作线程封送UI线程上委托的执行。如果是这种情况,那么两个线程都将死锁<代码>连接
阻止等待工作线程的UI线程<代码>控制。调用
阻止工作线程等待UI线程

用作线程间通信机制的变量应该是线程安全的。在本例中,您使用
RunBuilders
作为工作线程上的动作信号机制。问题在于,由于
RunBuilders
既没有标记为
volatile
,也没有从
lock
块中访问,因此其值无法可靠地传输到工作线程。您可以在一个线程中将其值设置为
true
,但另一个线程可以无限期地继续读取
false



1如果您发布更多代码,我可能能够提供更好的洞察力。具体来说,我想了解一下
Cam1Builder
Cam2Builder
正在做什么,特别是它正在阅读的部分
RunBuilders
,如果没有更多的代码,很难说清楚,但是您已经开始使用一些资源,但是您没有正确关闭它们

Join()等待线程完全关闭,并在返回之前释放所有资源。如果线程有任何BackgroundWorker任务,或者如果它有任何未显示仍在运行的备用任务,它将不会返回

由于BuildThread1和BuildThread2都正确返回并加入,您可以确定这不是其中之一,也不是他们正在做的任何事情。查看代码的其余部分。它有什么作用

编辑: 这很好:

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }


    Thread ControlThread;
    Thread BuildThread1;
    Thread BuildThread2;
    volatile bool RunBuilders = true;
    volatile bool RunControl = true;

    private void button1_Click(object sender, EventArgs e)
    {
        ControlThread = new Thread(new ThreadStart(Run));
        ControlThread.Start();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        RunControl = false;

        if (ControlThread != null)
        {
            while (ControlThread.IsAlive)
            {
                Thread.Sleep(100);
            }
            //somehow Join did not work
            ControlThread.Join();
        }
    }

    public void Run()
    {   //Known as Child1
        //code to setup coms is here

        //Launch Builder threads
        RunBuilders = true;

        //Known as Child2 and Child3
        BuildThread1 = new Thread(new ThreadStart(Cam1Builder));
        BuildThread2 = new Thread(new ThreadStart(Cam1Builder));
        BuildThread1.Start();
        BuildThread2.Start();

        while (RunControl)
        {
        //// Code that waits for coms and tosses data into lists
        }

        RunBuilders = false;

        //Wait for threads to terminate
        BuildThread1.Join();
        BuildThread2.Join();
    }


    public void Cam1Builder()
    {
        while ( RunBuilders )
        {

        }
    }
}
}

您是否尝试将RunBuilder更改为volatile?就个人而言,我不知道我是否会以这种方式跨线程使用bool,但如果要使用bool,它应该是可变的,以便所有线程都能看到更新,而不是JIT“缓存”的过时值


除此之外,我们还需要看看其他两个线程在做什么。

我们可以看一个简单的示例代码吗?我添加了一些示例代码。我删掉了所有的COM,没有包括Child2和Child3的实际内容。他们都结束得很好,虽然我通过他们的连接没有任何担心。它们的退出是由RunBuilders=false引起的。RunBuilders是否易变?否。应该是吗?RunBuilder仅由Child1更改,并且仅由Child2和Child3读取,但它们的联接方法都正常返回。好的,InsertBackgroundMonitor做什么?我不知道这个函数,谷歌搜索让我觉得它不是任何标准函数。我的Cam1Builder和Cam2Builder线程执行的任务几乎相同,区别在于它们监视两个不同的输入缓冲区。它们对RunBuilder的唯一用途是它们的包含循环,这只是一种声明