求助,C#如何安全的关闭线程,之后在重新打开这个线程?

时间:2022-05-13 23:47:53
程序运行时开启了一个线程,当点击一个按钮时需要开打一个窗体,此时需要关闭这个线程,当返回主界面时需要重新开启这个线程,求助怎么样才能安全的关闭和开启,我用的是thread.suspend来挂起线程,用thread.resume来重新开启现场,出现的问题是有的时候会出现死机的情况,求助怎样才能安全的实现以上功能,不会出现程序死机。

21 个解决方案

#1


线程方法是怎样的?

#2


this.Label1.InvokeEx(e => e.Text = DateTime.Now);  试试加入界面防止死机

#3


让线程sleep呢?

#4


suspend()、resume()这个方法已经过时了,并且是不被推荐的。    一个线程去强制停止另外一个正在运行的线程是有风险的。
如果你需要停止的线程是一个循环机制的,可以使用标志位,需要停止的线程去检查这个标志位,如果为TRUE就休眠,直到为false
才运行。  这是我已知最安全的方式了。

#5


https://msdn.microsoft.com/zh-cn/library/system.threading.thread.suspend(v=vs.100).aspx

#6


我觉得对待处理线程状态的操作问题之前,首先要搞清楚线程的几种状态的概念。

按照我个人对这个问题的理解,给楼主提供下面的思路,不知道可行性如何?

首先,要保证线程函数正常退出,实际上当线程函数执行完毕且正常退出之后,也就意味着这个线程也将“退场”(线程正常结束)。

我的想法是在你的线程函数中加一个While(新窗体.flag) 状态监视的循环,这个flag就是标识你是否已经打开了一个新的窗体。如果新打开了一个窗体,你就把flag这个变量置成flase,这个时候,线程函数就会跳出while循环,朝着线程函数的“最后”方向执行,指导退出线程函数,线程函数退出,那么线程也就结束了。

当再一次返回主界面的时候,再重新开启一下线程就可以。
这个思路的关键是要传递flag的值,可以在实例化新窗体的时候传值。在你的新窗体定义一个全局变量 public static flag=true;,构造函数中 flag=false;

这样就可以在你的线程函数中监视窗体的状态了。

#7


引用 1 楼 shingoscar 的回复:
线程方法是怎样的?


thread.start();开启线程后用需要关闭时用thread.suspend挂起,需要开启后用thread.resume恢复线程

#8


引用 2 楼 w6579106 的回复:
this.Label1.InvokeEx(e => e.Text = DateTime.Now);  试试加入界面防止死机


这个方法具体怎么用呢,方便给个具体样例出来嘛

#9


引用 7 楼 gold8fish 的回复:
Quote: 引用 1 楼 shingoscar 的回复:

线程方法是怎样的?


thread.start();开启线程后用需要关闭时用thread.suspend挂起,需要开启后用thread.resume恢复线程

线程函数是怎样的?不是问你是怎么操作的

#10


引用 4 楼 u013421223 的回复:
suspend()、resume()这个方法已经过时了,并且是不被推荐的。    一个线程去强制停止另外一个正在运行的线程是有风险的。
如果你需要停止的线程是一个循环机制的,可以使用标志位,需要停止的线程去检查这个标志位,如果为TRUE就休眠,直到为false
才运行。  这是我已知最安全的方式了。

 嗯,好的,还有割问题,要是我用thread.abort();方法关闭此线程,需要的时候在重开打开,会有什么问题吗

#11


引用 6 楼 Tidal_Choidi 的回复:
我觉得对待处理线程状态的操作问题之前,首先要搞清楚线程的几种状态的概念。

按照我个人对这个问题的理解,给楼主提供下面的思路,不知道可行性如何?

首先,要保证线程函数正常退出,实际上当线程函数执行完毕且正常退出之后,也就意味着这个线程也将“退场”(线程正常结束)。

我的想法是在你的线程函数中加一个While(新窗体.flag) 状态监视的循环,这个flag就是标识你是否已经打开了一个新的窗体。如果新打开了一个窗体,你就把flag这个变量置成flase,这个时候,线程函数就会跳出while循环,朝着线程函数的“最后”方向执行,指导退出线程函数,线程函数退出,那么线程也就结束了。

当再一次返回主界面的时候,再重新开启一下线程就可以。
这个思路的关键是要传递flag的值,可以在实例化新窗体的时候传值。在你的新窗体定义一个全局变量 public static flag=true;,构造函数中 flag=false;

这样就可以在你的线程函数中监视窗体的状态了。


嗯,好的,在请问一个问题,我要是用thread.abort();来中止这个线程,需要的时候再重新实例化线程并调用thread.start();再开始这个线程,这样会有什么问题吗?具体代码如下:
private void Exit_Click(object sender, EventArgs e)
        {
            if (Global.Power == "1")
            {
                t3.Abort();   //关闭t3线程
                mb.Close();
                Form manual = new Manual();
                manual.ShowDialog();
                if (manual.DialogResult == DialogResult.OK)
                {
                    if (mb.Open("COM3", Convert.ToInt32("9600"), 8, Parity.None, StopBits.One))
                    {
                        label18.Text = "Manual";
                        MessageBox.Show("COM3 Open Success!");
                        Thread.Sleep(50);
                        t3 = new Thread(DataShow);    //重新打开t3线程
                        t3.Start();
                    }
                    else
                    {
                        MessageBox.Show("串口打开失败,请检查线路!");
                    }
                }
            }
        }

#12


引用 9 楼 shingoscar 的回复:
Quote: 引用 7 楼 gold8fish 的回复:

Quote: 引用 1 楼 shingoscar 的回复:

线程方法是怎样的?


thread.start();开启线程后用需要关闭时用thread.suspend挂起,需要开启后用thread.resume恢复线程

线程函数是怎样的?不是问你是怎么操作的


好的,线程函数是这样的:
private void DataShow()
        {
            while (true)
            {
                Thread.Sleep(50);
              
                short[] values = new short[Convert.ToInt32("5") * 2];

                int length = Convert.ToInt32("5") * 2;
                pollStart = Convert.ToUInt16("15");//起始寄存器地址
                pollLength = Convert.ToUInt16(length.ToString());
                。。。。。。。。。。//一些列程序代码
                try
                {
                    while (!mb.SendFc3(Convert.ToByte("1"), pollStart, pollLength, ref values)) ;
                }
                catch (Exception err)
                {
                }
        }

#13


引用 10 楼 gold8fish 的回复:
Quote: 引用 4 楼 u013421223 的回复:

suspend()、resume()这个方法已经过时了,并且是不被推荐的。    一个线程去强制停止另外一个正在运行的线程是有风险的。
如果你需要停止的线程是一个循环机制的,可以使用标志位,需要停止的线程去检查这个标志位,如果为TRUE就休眠,直到为false
才运行。  这是我已知最安全的方式了。

 嗯,好的,还有割问题,要是我用thread.abort();方法关闭此线程,需要的时候在重开打开,会有什么问题吗


https://msdn.microsoft.com/zh-cn/library/5b50fdsz(v=vs.110).aspx   
 C#比做android最好的优势就是不*看官方文档,你居然不看。

#14


引用 12 楼 gold8fish 的回复:
Quote: 引用 9 楼 shingoscar 的回复:

Quote: 引用 7 楼 gold8fish 的回复:

Quote: 引用 1 楼 shingoscar 的回复:

线程方法是怎样的?


thread.start();开启线程后用需要关闭时用thread.suspend挂起,需要开启后用thread.resume恢复线程

线程函数是怎样的?不是问你是怎么操作的


好的,线程函数是这样的:
private void DataShow()
        {
            while (true)
            {
                Thread.Sleep(50);
              
                short[] values = new short[Convert.ToInt32("5") * 2];

                int length = Convert.ToInt32("5") * 2;
                pollStart = Convert.ToUInt16("15");//起始寄存器地址
                pollLength = Convert.ToUInt16(length.ToString());
                。。。。。。。。。。//一些列程序代码
                try
                {
                    while (!mb.SendFc3(Convert.ToByte("1"), pollStart, pollLength, ref values)) ;
                }
                catch (Exception err)
                {
                }
        }


在while后面再加

while(一个全局变量,窗体打开时为true,关闭时为false)
{
   Thread.Sleep(0)
}

#15


引用 11 楼 gold8fish 的回复:
Quote: 引用 6 楼 Tidal_Choidi 的回复:

我觉得对待处理线程状态的操作问题之前,首先要搞清楚线程的几种状态的概念。

按照我个人对这个问题的理解,给楼主提供下面的思路,不知道可行性如何?

首先,要保证线程函数正常退出,实际上当线程函数执行完毕且正常退出之后,也就意味着这个线程也将“退场”(线程正常结束)。

我的想法是在你的线程函数中加一个While(新窗体.flag) 状态监视的循环,这个flag就是标识你是否已经打开了一个新的窗体。如果新打开了一个窗体,你就把flag这个变量置成flase,这个时候,线程函数就会跳出while循环,朝着线程函数的“最后”方向执行,指导退出线程函数,线程函数退出,那么线程也就结束了。

当再一次返回主界面的时候,再重新开启一下线程就可以。
这个思路的关键是要传递flag的值,可以在实例化新窗体的时候传值。在你的新窗体定义一个全局变量 public static flag=true;,构造函数中 flag=false;

这样就可以在你的线程函数中监视窗体的状态了。


嗯,好的,在请问一个问题,我要是用thread.abort();来中止这个线程,需要的时候再重新实例化线程并调用thread.start();再开始这个线程,这样会有什么问题吗?具体代码如下:
private void Exit_Click(object sender, EventArgs e)
        {
            if (Global.Power == "1")
            {
                t3.Abort();   //关闭t3线程
                mb.Close();
                Form manual = new Manual();
                manual.ShowDialog();
                if (manual.DialogResult == DialogResult.OK)
                {
                    if (mb.Open("COM3", Convert.ToInt32("9600"), 8, Parity.None, StopBits.One))
                    {
                        label18.Text = "Manual";
                        MessageBox.Show("COM3 Open Success!");
                        Thread.Sleep(50);
                        t3 = new Thread(DataShow);    //重新打开t3线程
                        t3.Start();
                    }
                    else
                    {
                        MessageBox.Show("串口打开失败,请检查线路!");
                    }
                }
            }
        }

========================================================================================
"下面我们来解释一下Abort()方法是如何工作的。因为公用语言运行时管理了所有的托管的线程,同样它能在每个线程内抛出异常。Abort()方法能在目标线程中抛出一个ThreadAbortException异常从而导致目标线程的终止。不过Abort()方法被调用后,目标线程可能并不是马上就终止了。因为只要目标线程正在调用非托管的代码而且还没有返回的话,该线程就不会立即终止。而如果目标线程在调用非托管的代码而且陷入了一个死循环的话,该目标线程就根本不会终止。不过这种情况只是一些特例,更多的情况是目标线程在调用托管的代码,一旦Abort()被调用那么该线程就立即终止了。 "

#16


引用 15 楼 Tidal_Choidi 的回复:
Quote: 引用 11 楼 gold8fish 的回复:

Quote: 引用 6 楼 Tidal_Choidi 的回复:

我觉得对待处理线程状态的操作问题之前,首先要搞清楚线程的几种状态的概念。

按照我个人对这个问题的理解,给楼主提供下面的思路,不知道可行性如何?

首先,要保证线程函数正常退出,实际上当线程函数执行完毕且正常退出之后,也就意味着这个线程也将“退场”(线程正常结束)。

我的想法是在你的线程函数中加一个While(新窗体.flag) 状态监视的循环,这个flag就是标识你是否已经打开了一个新的窗体。如果新打开了一个窗体,你就把flag这个变量置成flase,这个时候,线程函数就会跳出while循环,朝着线程函数的“最后”方向执行,指导退出线程函数,线程函数退出,那么线程也就结束了。

当再一次返回主界面的时候,再重新开启一下线程就可以。
这个思路的关键是要传递flag的值,可以在实例化新窗体的时候传值。在你的新窗体定义一个全局变量 public static flag=true;,构造函数中 flag=false;

这样就可以在你的线程函数中监视窗体的状态了。


嗯,好的,在请问一个问题,我要是用thread.abort();来中止这个线程,需要的时候再重新实例化线程并调用thread.start();再开始这个线程,这样会有什么问题吗?具体代码如下:
private void Exit_Click(object sender, EventArgs e)
        {
            if (Global.Power == "1")
            {
                t3.Abort();   //关闭t3线程
                mb.Close();
                Form manual = new Manual();
                manual.ShowDialog();
                if (manual.DialogResult == DialogResult.OK)
                {
                    if (mb.Open("COM3", Convert.ToInt32("9600"), 8, Parity.None, StopBits.One))
                    {
                        label18.Text = "Manual";
                        MessageBox.Show("COM3 Open Success!");
                        Thread.Sleep(50);
                        t3 = new Thread(DataShow);    //重新打开t3线程
                        t3.Start();
                    }
                    else
                    {
                        MessageBox.Show("串口打开失败,请检查线路!");
                    }
                }
            }
        }

========================================================================================
"下面我们来解释一下Abort()方法是如何工作的。因为公用语言运行时管理了所有的托管的线程,同样它能在每个线程内抛出异常。Abort()方法能在目标线程中抛出一个ThreadAbortException异常从而导致目标线程的终止。不过Abort()方法被调用后,目标线程可能并不是马上就终止了。因为只要目标线程正在调用非托管的代码而且还没有返回的话,该线程就不会立即终止。而如果目标线程在调用非托管的代码而且陷入了一个死循环的话,该目标线程就根本不会终止。不过这种情况只是一些特例,更多的情况是目标线程在调用托管的代码,一旦Abort()被调用那么该线程就立即终止了。 "


好的,也就是说,如果我的线程函数中不存在死循环,这个方法是可以正常使用的,我的线程函数是用来串口通讯的,实时读取串口数据,要是串口通讯出现卡死,就是陷入死循环的话,以上方法的线程事中止不了的,再次开启这个线程会出现问题。

#17


4楼、6楼都讲的比较到位了
线程要安全关闭,只能靠自行退出,否则就会有资源泄露或者崩溃的风险

#18


引用 14 楼 u013421223 的回复:
Quote: 引用 12 楼 gold8fish 的回复:

Quote: 引用 9 楼 shingoscar 的回复:

Quote: 引用 7 楼 gold8fish 的回复:

Quote: 引用 1 楼 shingoscar 的回复:

线程方法是怎样的?


thread.start();开启线程后用需要关闭时用thread.suspend挂起,需要开启后用thread.resume恢复线程

线程函数是怎样的?不是问你是怎么操作的


好的,线程函数是这样的:
private void DataShow()
        {
            while (true)
            {
                Thread.Sleep(50);
              
                short[] values = new short[Convert.ToInt32("5") * 2];

                int length = Convert.ToInt32("5") * 2;
                pollStart = Convert.ToUInt16("15");//起始寄存器地址
                pollLength = Convert.ToUInt16(length.ToString());
                。。。。。。。。。。//一些列程序代码
                try
                {
                    while (!mb.SendFc3(Convert.ToByte("1"), pollStart, pollLength, ref values)) ;
                }
                catch (Exception err)
                {
                }
        }


在while后面再加

while(一个全局变量,窗体打开时为true,关闭时为false)
{
   Thread.Sleep(0)
}


引用 14 楼 u013421223 的回复:
Quote: 引用 12 楼 gold8fish 的回复:

Quote: 引用 9 楼 shingoscar 的回复:

Quote: 引用 7 楼 gold8fish 的回复:

Quote: 引用 1 楼 shingoscar 的回复:

线程方法是怎样的?


thread.start();开启线程后用需要关闭时用thread.suspend挂起,需要开启后用thread.resume恢复线程

线程函数是怎样的?不是问你是怎么操作的


好的,线程函数是这样的:
private void DataShow()
        {
            while (true)
            {
                Thread.Sleep(50);
              
                short[] values = new short[Convert.ToInt32("5") * 2];

                int length = Convert.ToInt32("5") * 2;
                pollStart = Convert.ToUInt16("15");//起始寄存器地址
                pollLength = Convert.ToUInt16(length.ToString());
                。。。。。。。。。。//一些列程序代码
                try
                {
                    while (!mb.SendFc3(Convert.ToByte("1"), pollStart, pollLength, ref values)) ;
                }
                catch (Exception err)
                {
                }
        }


在while后面再加

while(一个全局变量,窗体打开时为true,关闭时为false)
{
   Thread.Sleep(0)
}


如果需要再次开启线程,只需要将这个全局变量值置位true嘛?

#19


引用 6 楼 Tidal_Choidi 的回复:
我觉得对待处理线程状态的操作问题之前,首先要搞清楚线程的几种状态的概念。

按照我个人对这个问题的理解,给楼主提供下面的思路,不知道可行性如何?

首先,要保证线程函数正常退出,实际上当线程函数执行完毕且正常退出之后,也就意味着这个线程也将“退场”(线程正常结束)。

我的想法是在你的线程函数中加一个While(新窗体.flag) 状态监视的循环,这个flag就是标识你是否已经打开了一个新的窗体。如果新打开了一个窗体,你就把flag这个变量置成flase,这个时候,线程函数就会跳出while循环,朝着线程函数的“最后”方向执行,指导退出线程函数,线程函数退出,那么线程也就结束了。

当再一次返回主界面的时候,再重新开启一下线程就可以。
这个思路的关键是要传递flag的值,可以在实例化新窗体的时候传值。在你的新窗体定义一个全局变量 public static flag=true;,构造函数中 flag=false;

这样就可以在你的线程函数中监视窗体的状态了。


用了您说的方法,安全关闭这个线程后,我再次开启这个线程是把flag设为true,将thread.start();是这个步骤嘛?

#20


引用 6 楼 Tidal_Choidi 的回复:
我觉得对待处理线程状态的操作问题之前,首先要搞清楚线程的几种状态的概念。

按照我个人对这个问题的理解,给楼主提供下面的思路,不知道可行性如何?

首先,要保证线程函数正常退出,实际上当线程函数执行完毕且正常退出之后,也就意味着这个线程也将“退场”(线程正常结束)。

我的想法是在你的线程函数中加一个While(新窗体.flag) 状态监视的循环,这个flag就是标识你是否已经打开了一个新的窗体。如果新打开了一个窗体,你就把flag这个变量置成flase,这个时候,线程函数就会跳出while循环,朝着线程函数的“最后”方向执行,指导退出线程函数,线程函数退出,那么线程也就结束了。

当再一次返回主界面的时候,再重新开启一下线程就可以。
这个思路的关键是要传递flag的值,可以在实例化新窗体的时候传值。在你的新窗体定义一个全局变量 public static flag=true;,构造函数中 flag=false;

这样就可以在你的线程函数中监视窗体的状态了。


用这种方法试了一下,发现重新开启线程后,线程有的时候会开启失败,我的指导退出步骤为:
在线程函的while为false后,用return结束函数,然后需要重新开启线程时用thread.start开启

#21


引用 20 楼 gold8fish 的回复:
Quote: 引用 6 楼 Tidal_Choidi 的回复:

我觉得对待处理线程状态的操作问题之前,首先要搞清楚线程的几种状态的概念。

按照我个人对这个问题的理解,给楼主提供下面的思路,不知道可行性如何?

首先,要保证线程函数正常退出,实际上当线程函数执行完毕且正常退出之后,也就意味着这个线程也将“退场”(线程正常结束)。

我的想法是在你的线程函数中加一个While(新窗体.flag) 状态监视的循环,这个flag就是标识你是否已经打开了一个新的窗体。如果新打开了一个窗体,你就把flag这个变量置成flase,这个时候,线程函数就会跳出while循环,朝着线程函数的“最后”方向执行,指导退出线程函数,线程函数退出,那么线程也就结束了。

当再一次返回主界面的时候,再重新开启一下线程就可以。
这个思路的关键是要传递flag的值,可以在实例化新窗体的时候传值。在你的新窗体定义一个全局变量 public static flag=true;,构造函数中 flag=false;

这样就可以在你的线程函数中监视窗体的状态了。


用这种方法试了一下,发现重新开启线程后,线程有的时候会开启失败,我的指导退出步骤为:
在线程函的while为false后,用return结束函数,然后需要重新开启线程时用thread.start开启



====================================================================================
怎么个开启失败呢?你确定是线程开启失败?可以在你要执行的线程函数中加入断点,判断一下每次开启线程的时候是否能执行到断点处。提醒你一下:有时候你开启线程并不是线程函数就会按照咱们想象的那样瞬间就执行了,因为线程的调度和优先级的原因,会有延迟的,但只是执行的时间早晚的问题,理论上是一定能够执行到线程函数的断点处的。

#1


线程方法是怎样的?

#2


this.Label1.InvokeEx(e => e.Text = DateTime.Now);  试试加入界面防止死机

#3


让线程sleep呢?

#4


suspend()、resume()这个方法已经过时了,并且是不被推荐的。    一个线程去强制停止另外一个正在运行的线程是有风险的。
如果你需要停止的线程是一个循环机制的,可以使用标志位,需要停止的线程去检查这个标志位,如果为TRUE就休眠,直到为false
才运行。  这是我已知最安全的方式了。

#5


https://msdn.microsoft.com/zh-cn/library/system.threading.thread.suspend(v=vs.100).aspx

#6


我觉得对待处理线程状态的操作问题之前,首先要搞清楚线程的几种状态的概念。

按照我个人对这个问题的理解,给楼主提供下面的思路,不知道可行性如何?

首先,要保证线程函数正常退出,实际上当线程函数执行完毕且正常退出之后,也就意味着这个线程也将“退场”(线程正常结束)。

我的想法是在你的线程函数中加一个While(新窗体.flag) 状态监视的循环,这个flag就是标识你是否已经打开了一个新的窗体。如果新打开了一个窗体,你就把flag这个变量置成flase,这个时候,线程函数就会跳出while循环,朝着线程函数的“最后”方向执行,指导退出线程函数,线程函数退出,那么线程也就结束了。

当再一次返回主界面的时候,再重新开启一下线程就可以。
这个思路的关键是要传递flag的值,可以在实例化新窗体的时候传值。在你的新窗体定义一个全局变量 public static flag=true;,构造函数中 flag=false;

这样就可以在你的线程函数中监视窗体的状态了。

#7


引用 1 楼 shingoscar 的回复:
线程方法是怎样的?


thread.start();开启线程后用需要关闭时用thread.suspend挂起,需要开启后用thread.resume恢复线程

#8


引用 2 楼 w6579106 的回复:
this.Label1.InvokeEx(e => e.Text = DateTime.Now);  试试加入界面防止死机


这个方法具体怎么用呢,方便给个具体样例出来嘛

#9


引用 7 楼 gold8fish 的回复:
Quote: 引用 1 楼 shingoscar 的回复:

线程方法是怎样的?


thread.start();开启线程后用需要关闭时用thread.suspend挂起,需要开启后用thread.resume恢复线程

线程函数是怎样的?不是问你是怎么操作的

#10


引用 4 楼 u013421223 的回复:
suspend()、resume()这个方法已经过时了,并且是不被推荐的。    一个线程去强制停止另外一个正在运行的线程是有风险的。
如果你需要停止的线程是一个循环机制的,可以使用标志位,需要停止的线程去检查这个标志位,如果为TRUE就休眠,直到为false
才运行。  这是我已知最安全的方式了。

 嗯,好的,还有割问题,要是我用thread.abort();方法关闭此线程,需要的时候在重开打开,会有什么问题吗

#11


引用 6 楼 Tidal_Choidi 的回复:
我觉得对待处理线程状态的操作问题之前,首先要搞清楚线程的几种状态的概念。

按照我个人对这个问题的理解,给楼主提供下面的思路,不知道可行性如何?

首先,要保证线程函数正常退出,实际上当线程函数执行完毕且正常退出之后,也就意味着这个线程也将“退场”(线程正常结束)。

我的想法是在你的线程函数中加一个While(新窗体.flag) 状态监视的循环,这个flag就是标识你是否已经打开了一个新的窗体。如果新打开了一个窗体,你就把flag这个变量置成flase,这个时候,线程函数就会跳出while循环,朝着线程函数的“最后”方向执行,指导退出线程函数,线程函数退出,那么线程也就结束了。

当再一次返回主界面的时候,再重新开启一下线程就可以。
这个思路的关键是要传递flag的值,可以在实例化新窗体的时候传值。在你的新窗体定义一个全局变量 public static flag=true;,构造函数中 flag=false;

这样就可以在你的线程函数中监视窗体的状态了。


嗯,好的,在请问一个问题,我要是用thread.abort();来中止这个线程,需要的时候再重新实例化线程并调用thread.start();再开始这个线程,这样会有什么问题吗?具体代码如下:
private void Exit_Click(object sender, EventArgs e)
        {
            if (Global.Power == "1")
            {
                t3.Abort();   //关闭t3线程
                mb.Close();
                Form manual = new Manual();
                manual.ShowDialog();
                if (manual.DialogResult == DialogResult.OK)
                {
                    if (mb.Open("COM3", Convert.ToInt32("9600"), 8, Parity.None, StopBits.One))
                    {
                        label18.Text = "Manual";
                        MessageBox.Show("COM3 Open Success!");
                        Thread.Sleep(50);
                        t3 = new Thread(DataShow);    //重新打开t3线程
                        t3.Start();
                    }
                    else
                    {
                        MessageBox.Show("串口打开失败,请检查线路!");
                    }
                }
            }
        }

#12


引用 9 楼 shingoscar 的回复:
Quote: 引用 7 楼 gold8fish 的回复:

Quote: 引用 1 楼 shingoscar 的回复:

线程方法是怎样的?


thread.start();开启线程后用需要关闭时用thread.suspend挂起,需要开启后用thread.resume恢复线程

线程函数是怎样的?不是问你是怎么操作的


好的,线程函数是这样的:
private void DataShow()
        {
            while (true)
            {
                Thread.Sleep(50);
              
                short[] values = new short[Convert.ToInt32("5") * 2];

                int length = Convert.ToInt32("5") * 2;
                pollStart = Convert.ToUInt16("15");//起始寄存器地址
                pollLength = Convert.ToUInt16(length.ToString());
                。。。。。。。。。。//一些列程序代码
                try
                {
                    while (!mb.SendFc3(Convert.ToByte("1"), pollStart, pollLength, ref values)) ;
                }
                catch (Exception err)
                {
                }
        }

#13


引用 10 楼 gold8fish 的回复:
Quote: 引用 4 楼 u013421223 的回复:

suspend()、resume()这个方法已经过时了,并且是不被推荐的。    一个线程去强制停止另外一个正在运行的线程是有风险的。
如果你需要停止的线程是一个循环机制的,可以使用标志位,需要停止的线程去检查这个标志位,如果为TRUE就休眠,直到为false
才运行。  这是我已知最安全的方式了。

 嗯,好的,还有割问题,要是我用thread.abort();方法关闭此线程,需要的时候在重开打开,会有什么问题吗


https://msdn.microsoft.com/zh-cn/library/5b50fdsz(v=vs.110).aspx   
 C#比做android最好的优势就是不*看官方文档,你居然不看。

#14


引用 12 楼 gold8fish 的回复:
Quote: 引用 9 楼 shingoscar 的回复:

Quote: 引用 7 楼 gold8fish 的回复:

Quote: 引用 1 楼 shingoscar 的回复:

线程方法是怎样的?


thread.start();开启线程后用需要关闭时用thread.suspend挂起,需要开启后用thread.resume恢复线程

线程函数是怎样的?不是问你是怎么操作的


好的,线程函数是这样的:
private void DataShow()
        {
            while (true)
            {
                Thread.Sleep(50);
              
                short[] values = new short[Convert.ToInt32("5") * 2];

                int length = Convert.ToInt32("5") * 2;
                pollStart = Convert.ToUInt16("15");//起始寄存器地址
                pollLength = Convert.ToUInt16(length.ToString());
                。。。。。。。。。。//一些列程序代码
                try
                {
                    while (!mb.SendFc3(Convert.ToByte("1"), pollStart, pollLength, ref values)) ;
                }
                catch (Exception err)
                {
                }
        }


在while后面再加

while(一个全局变量,窗体打开时为true,关闭时为false)
{
   Thread.Sleep(0)
}

#15


引用 11 楼 gold8fish 的回复:
Quote: 引用 6 楼 Tidal_Choidi 的回复:

我觉得对待处理线程状态的操作问题之前,首先要搞清楚线程的几种状态的概念。

按照我个人对这个问题的理解,给楼主提供下面的思路,不知道可行性如何?

首先,要保证线程函数正常退出,实际上当线程函数执行完毕且正常退出之后,也就意味着这个线程也将“退场”(线程正常结束)。

我的想法是在你的线程函数中加一个While(新窗体.flag) 状态监视的循环,这个flag就是标识你是否已经打开了一个新的窗体。如果新打开了一个窗体,你就把flag这个变量置成flase,这个时候,线程函数就会跳出while循环,朝着线程函数的“最后”方向执行,指导退出线程函数,线程函数退出,那么线程也就结束了。

当再一次返回主界面的时候,再重新开启一下线程就可以。
这个思路的关键是要传递flag的值,可以在实例化新窗体的时候传值。在你的新窗体定义一个全局变量 public static flag=true;,构造函数中 flag=false;

这样就可以在你的线程函数中监视窗体的状态了。


嗯,好的,在请问一个问题,我要是用thread.abort();来中止这个线程,需要的时候再重新实例化线程并调用thread.start();再开始这个线程,这样会有什么问题吗?具体代码如下:
private void Exit_Click(object sender, EventArgs e)
        {
            if (Global.Power == "1")
            {
                t3.Abort();   //关闭t3线程
                mb.Close();
                Form manual = new Manual();
                manual.ShowDialog();
                if (manual.DialogResult == DialogResult.OK)
                {
                    if (mb.Open("COM3", Convert.ToInt32("9600"), 8, Parity.None, StopBits.One))
                    {
                        label18.Text = "Manual";
                        MessageBox.Show("COM3 Open Success!");
                        Thread.Sleep(50);
                        t3 = new Thread(DataShow);    //重新打开t3线程
                        t3.Start();
                    }
                    else
                    {
                        MessageBox.Show("串口打开失败,请检查线路!");
                    }
                }
            }
        }

========================================================================================
"下面我们来解释一下Abort()方法是如何工作的。因为公用语言运行时管理了所有的托管的线程,同样它能在每个线程内抛出异常。Abort()方法能在目标线程中抛出一个ThreadAbortException异常从而导致目标线程的终止。不过Abort()方法被调用后,目标线程可能并不是马上就终止了。因为只要目标线程正在调用非托管的代码而且还没有返回的话,该线程就不会立即终止。而如果目标线程在调用非托管的代码而且陷入了一个死循环的话,该目标线程就根本不会终止。不过这种情况只是一些特例,更多的情况是目标线程在调用托管的代码,一旦Abort()被调用那么该线程就立即终止了。 "

#16


引用 15 楼 Tidal_Choidi 的回复:
Quote: 引用 11 楼 gold8fish 的回复:

Quote: 引用 6 楼 Tidal_Choidi 的回复:

我觉得对待处理线程状态的操作问题之前,首先要搞清楚线程的几种状态的概念。

按照我个人对这个问题的理解,给楼主提供下面的思路,不知道可行性如何?

首先,要保证线程函数正常退出,实际上当线程函数执行完毕且正常退出之后,也就意味着这个线程也将“退场”(线程正常结束)。

我的想法是在你的线程函数中加一个While(新窗体.flag) 状态监视的循环,这个flag就是标识你是否已经打开了一个新的窗体。如果新打开了一个窗体,你就把flag这个变量置成flase,这个时候,线程函数就会跳出while循环,朝着线程函数的“最后”方向执行,指导退出线程函数,线程函数退出,那么线程也就结束了。

当再一次返回主界面的时候,再重新开启一下线程就可以。
这个思路的关键是要传递flag的值,可以在实例化新窗体的时候传值。在你的新窗体定义一个全局变量 public static flag=true;,构造函数中 flag=false;

这样就可以在你的线程函数中监视窗体的状态了。


嗯,好的,在请问一个问题,我要是用thread.abort();来中止这个线程,需要的时候再重新实例化线程并调用thread.start();再开始这个线程,这样会有什么问题吗?具体代码如下:
private void Exit_Click(object sender, EventArgs e)
        {
            if (Global.Power == "1")
            {
                t3.Abort();   //关闭t3线程
                mb.Close();
                Form manual = new Manual();
                manual.ShowDialog();
                if (manual.DialogResult == DialogResult.OK)
                {
                    if (mb.Open("COM3", Convert.ToInt32("9600"), 8, Parity.None, StopBits.One))
                    {
                        label18.Text = "Manual";
                        MessageBox.Show("COM3 Open Success!");
                        Thread.Sleep(50);
                        t3 = new Thread(DataShow);    //重新打开t3线程
                        t3.Start();
                    }
                    else
                    {
                        MessageBox.Show("串口打开失败,请检查线路!");
                    }
                }
            }
        }

========================================================================================
"下面我们来解释一下Abort()方法是如何工作的。因为公用语言运行时管理了所有的托管的线程,同样它能在每个线程内抛出异常。Abort()方法能在目标线程中抛出一个ThreadAbortException异常从而导致目标线程的终止。不过Abort()方法被调用后,目标线程可能并不是马上就终止了。因为只要目标线程正在调用非托管的代码而且还没有返回的话,该线程就不会立即终止。而如果目标线程在调用非托管的代码而且陷入了一个死循环的话,该目标线程就根本不会终止。不过这种情况只是一些特例,更多的情况是目标线程在调用托管的代码,一旦Abort()被调用那么该线程就立即终止了。 "


好的,也就是说,如果我的线程函数中不存在死循环,这个方法是可以正常使用的,我的线程函数是用来串口通讯的,实时读取串口数据,要是串口通讯出现卡死,就是陷入死循环的话,以上方法的线程事中止不了的,再次开启这个线程会出现问题。

#17


4楼、6楼都讲的比较到位了
线程要安全关闭,只能靠自行退出,否则就会有资源泄露或者崩溃的风险

#18


引用 14 楼 u013421223 的回复:
Quote: 引用 12 楼 gold8fish 的回复:

Quote: 引用 9 楼 shingoscar 的回复:

Quote: 引用 7 楼 gold8fish 的回复:

Quote: 引用 1 楼 shingoscar 的回复:

线程方法是怎样的?


thread.start();开启线程后用需要关闭时用thread.suspend挂起,需要开启后用thread.resume恢复线程

线程函数是怎样的?不是问你是怎么操作的


好的,线程函数是这样的:
private void DataShow()
        {
            while (true)
            {
                Thread.Sleep(50);
              
                short[] values = new short[Convert.ToInt32("5") * 2];

                int length = Convert.ToInt32("5") * 2;
                pollStart = Convert.ToUInt16("15");//起始寄存器地址
                pollLength = Convert.ToUInt16(length.ToString());
                。。。。。。。。。。//一些列程序代码
                try
                {
                    while (!mb.SendFc3(Convert.ToByte("1"), pollStart, pollLength, ref values)) ;
                }
                catch (Exception err)
                {
                }
        }


在while后面再加

while(一个全局变量,窗体打开时为true,关闭时为false)
{
   Thread.Sleep(0)
}


引用 14 楼 u013421223 的回复:
Quote: 引用 12 楼 gold8fish 的回复:

Quote: 引用 9 楼 shingoscar 的回复:

Quote: 引用 7 楼 gold8fish 的回复:

Quote: 引用 1 楼 shingoscar 的回复:

线程方法是怎样的?


thread.start();开启线程后用需要关闭时用thread.suspend挂起,需要开启后用thread.resume恢复线程

线程函数是怎样的?不是问你是怎么操作的


好的,线程函数是这样的:
private void DataShow()
        {
            while (true)
            {
                Thread.Sleep(50);
              
                short[] values = new short[Convert.ToInt32("5") * 2];

                int length = Convert.ToInt32("5") * 2;
                pollStart = Convert.ToUInt16("15");//起始寄存器地址
                pollLength = Convert.ToUInt16(length.ToString());
                。。。。。。。。。。//一些列程序代码
                try
                {
                    while (!mb.SendFc3(Convert.ToByte("1"), pollStart, pollLength, ref values)) ;
                }
                catch (Exception err)
                {
                }
        }


在while后面再加

while(一个全局变量,窗体打开时为true,关闭时为false)
{
   Thread.Sleep(0)
}


如果需要再次开启线程,只需要将这个全局变量值置位true嘛?

#19


引用 6 楼 Tidal_Choidi 的回复:
我觉得对待处理线程状态的操作问题之前,首先要搞清楚线程的几种状态的概念。

按照我个人对这个问题的理解,给楼主提供下面的思路,不知道可行性如何?

首先,要保证线程函数正常退出,实际上当线程函数执行完毕且正常退出之后,也就意味着这个线程也将“退场”(线程正常结束)。

我的想法是在你的线程函数中加一个While(新窗体.flag) 状态监视的循环,这个flag就是标识你是否已经打开了一个新的窗体。如果新打开了一个窗体,你就把flag这个变量置成flase,这个时候,线程函数就会跳出while循环,朝着线程函数的“最后”方向执行,指导退出线程函数,线程函数退出,那么线程也就结束了。

当再一次返回主界面的时候,再重新开启一下线程就可以。
这个思路的关键是要传递flag的值,可以在实例化新窗体的时候传值。在你的新窗体定义一个全局变量 public static flag=true;,构造函数中 flag=false;

这样就可以在你的线程函数中监视窗体的状态了。


用了您说的方法,安全关闭这个线程后,我再次开启这个线程是把flag设为true,将thread.start();是这个步骤嘛?

#20


引用 6 楼 Tidal_Choidi 的回复:
我觉得对待处理线程状态的操作问题之前,首先要搞清楚线程的几种状态的概念。

按照我个人对这个问题的理解,给楼主提供下面的思路,不知道可行性如何?

首先,要保证线程函数正常退出,实际上当线程函数执行完毕且正常退出之后,也就意味着这个线程也将“退场”(线程正常结束)。

我的想法是在你的线程函数中加一个While(新窗体.flag) 状态监视的循环,这个flag就是标识你是否已经打开了一个新的窗体。如果新打开了一个窗体,你就把flag这个变量置成flase,这个时候,线程函数就会跳出while循环,朝着线程函数的“最后”方向执行,指导退出线程函数,线程函数退出,那么线程也就结束了。

当再一次返回主界面的时候,再重新开启一下线程就可以。
这个思路的关键是要传递flag的值,可以在实例化新窗体的时候传值。在你的新窗体定义一个全局变量 public static flag=true;,构造函数中 flag=false;

这样就可以在你的线程函数中监视窗体的状态了。


用这种方法试了一下,发现重新开启线程后,线程有的时候会开启失败,我的指导退出步骤为:
在线程函的while为false后,用return结束函数,然后需要重新开启线程时用thread.start开启

#21


引用 20 楼 gold8fish 的回复:
Quote: 引用 6 楼 Tidal_Choidi 的回复:

我觉得对待处理线程状态的操作问题之前,首先要搞清楚线程的几种状态的概念。

按照我个人对这个问题的理解,给楼主提供下面的思路,不知道可行性如何?

首先,要保证线程函数正常退出,实际上当线程函数执行完毕且正常退出之后,也就意味着这个线程也将“退场”(线程正常结束)。

我的想法是在你的线程函数中加一个While(新窗体.flag) 状态监视的循环,这个flag就是标识你是否已经打开了一个新的窗体。如果新打开了一个窗体,你就把flag这个变量置成flase,这个时候,线程函数就会跳出while循环,朝着线程函数的“最后”方向执行,指导退出线程函数,线程函数退出,那么线程也就结束了。

当再一次返回主界面的时候,再重新开启一下线程就可以。
这个思路的关键是要传递flag的值,可以在实例化新窗体的时候传值。在你的新窗体定义一个全局变量 public static flag=true;,构造函数中 flag=false;

这样就可以在你的线程函数中监视窗体的状态了。


用这种方法试了一下,发现重新开启线程后,线程有的时候会开启失败,我的指导退出步骤为:
在线程函的while为false后,用return结束函数,然后需要重新开启线程时用thread.start开启



====================================================================================
怎么个开启失败呢?你确定是线程开启失败?可以在你要执行的线程函数中加入断点,判断一下每次开启线程的时候是否能执行到断点处。提醒你一下:有时候你开启线程并不是线程函数就会按照咱们想象的那样瞬间就执行了,因为线程的调度和优先级的原因,会有延迟的,但只是执行的时间早晚的问题,理论上是一定能够执行到线程函数的断点处的。