简体   繁体   English

Windows窗体C#中的多线程

[英]Multithreading in windows forms C#

In a windows application, apart from main thread there is another thread which does a long run operation for every minute and updates the UI using Invoke method. 在Windows应用程序中,除主线程外,还有另一个线程每分钟进行一次长时间运行操作,并使用Invoke方法更新UI。

How can we terminate the another thread gracefully when it is in sleeping state? 当另一个线程处于睡眠状态时,我们如何优雅地终止它?

Is it a right choice of using sleep here? 在这里使用睡眠是正确的选择吗?

Instead of making the thread once and then terminating, perhaps use a form timer to trigger a background worker thread every 60000 milliseconds? 而不是先创建线程然后终止,而是使用表单计时器每60000毫秒触发一个后台工作线程? You then don't need to sleep the background thread at all. 然后,您根本不需要休眠后台线程。

This means you only need to stop the timer to stop more background tasks from being spawned, but obviously this doesn't stop any currently active background thread. 这意味着您只需要停止计时器即可停止生成更多后台任务,但是显然这不会停止任何当前活动的后台线程。

Threads should very rarely be aborted, as there isn't any great mechanism available for doing it with any consistency. 线程应该很少被中止,因为没有任何强大的机制可以实现任何一致性。 There are various guards such as critical code markers. 有各种保护措施,例如关键代码标记。 However, I think it's best to have the long running code poll for cancellation, then you can code your own logic for abandoning ship and returning early. 但是,我认为最好将长期运行的代码轮询以进行取消,然后可以编写自己的逻辑以放弃船舰并提早返回。 Note , this is not the same as aborting a thread forcefully. 注意 ,这与强行中止线程不同。

I don't think sleep is the right choice in almost any circumstances. 我认为在任何情况下睡眠都不是正确的选择。

For example: 例如:

private bool _askedToCancel;

public void lonRunThread()
{
    if (!_askedToCancel)
    {
        Operation1();
        Invoke(new UpdateDelegate(updateState));
    }

    if (!_askedToCancel)
    {    
        Operation2();
        Invoke(new UpdateDelegate(updateState));
    }
}

Seems a little messy, however you retain very good control over what logic is performed if you refuse to abort threads forcefully and instead use the cancellation approach. 似乎有些混乱,但是,如果您拒绝强行中止线程,而是使用取消方法,则可以很好地控制执行的逻辑。

Because this isn't critical code, and because actions on booleans are atomic, you should be safe having both threads talk to the bool without any locking. 因为这不是关键代码,并且因为对布尔值的操作是原子性的,所以两个线程在不进行任何锁定的情况下与bool进行通信应该是安全的。 And even if it's not truly safe, the only result is some more work is done. 即使不是真正安全,唯一的结果就是要做更多的工作。

You can always set the thread to be a background thread, that way when the application exits the thread will automagically be stopped. 您始终可以将线程设置为后台线程,这样,当应用程序退出时,该线程将自动停止。

When do you want the thread to be stopped? 您何时希望停止线程?

If you want it stopped in mid-operation a boolean flag would be appropriate. 如果您希望它在操作过程中停止,则布尔标志将是适当的。

So instead of 所以代替

while(true)

You would do something like 你会做类似的事情

while(exit == false)

I would change the while(true) in longRunThread method and make it 我会在longRunThread方法中更改while(true)并使其

while (_RunLongThread)

then in the TestForm I would declare the private Boolean _RunLongThread = true and set it to false from whichever method needs to stop the long running thread. 然后在TestForm中,我将声明私有布尔值_RunLongThread = true并将其从需要停止长时间运行的线程的任何方法设置为false。

Thats a "graceful" way of stopping it ie waiting to complete its current task and then terminates 那是停止它的“优美”方式,即等待完成其当前任务然后终止

There is no such thing as graceful thread termination. 没有诸如正常线程终止之类的东西。 Instead, your thread should be instructed to stop doing it's job once it's no longer needed. 相反,应该指示您的线程在不再需要时停止执行其工作。 You could do this by creating class to hold worker thread parameters inside which you store information whether work should be stopped, and pass an object of that class to the thread. 您可以通过创建类来保存工作线程参数来实现此目的,在该线程中存储是否应停止工作的信息,并将该类的对象传递给线程。

public class WorkerParams
{
    public bool Stop = false;
}

private void TestForm_Load(object sender, EventArgs e)
{
    _thread = new Thread(lonRunThread);
    _thread.Start(new WorkerParams());
}

public void lonRunThread(object argument)
{
    WorkerParams param = argument as WorkerParams;
    DateTime lastExec = DateTime.MinValue;
    while(!param.Stop)
    {
        if (new TimeSpan(DateTime.Now.Ticks - lastExec.Ticks).TotalSeconds >= 60)
        {
            Operation1();
            Invoke(new UpdateDelegate(updateState));
            Operation2();
            Invoke(new UpdateDelegate(updateState));
            lastExec = DateTime.Now;
        }
        Thread.Sleep(500);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM