这个thread.abort()正常且安全吗? [英] Is this thread.abort() normal and safe?

查看:82
本文介绍了这个thread.abort()正常且安全吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个自定义自动完成控件,当用户按下一个键时,它将在另一个线程上查询数据库服务器(使用远程处理).当用户快速键入时,程序必须取消先前执行的请求/线程.

I created a custom autocomplete control, when the user press a key it queries the database server (using Remoting) on another thread. When the user types very fast, the program must cancel the previously executing request/thread.

我以前首先将其实现为AsyncCallback,但我发现它很麻烦,要遵循的内部规则过多(例如AsyncResult,AsyncState,EndInvoke),另外您还必须检测BeginInvoke'd对象的线程,以便可以终止先前执行的线程.此外,如果我继续执行AsyncCallback,则那些AsyncCallbacks上没有任何方法可以正确终止先前执行的线程.

I previously implemented it as AsyncCallback first, but i find it cumbersome, too many house rules to follow (e.g. AsyncResult, AsyncState, EndInvoke) plus you have to detect the thread of the BeginInvoke'd object, so you can terminate the previously executing thread. Besides if I continued the AsyncCallback, there's no method on those AsyncCallbacks that can properly terminate previously executing thread.

EndInvoke无法终止线程,它仍将完成要终止的线程的操作.我仍然会最终在线程上使用Abort().

EndInvoke cannot terminate the thread, it would still complete the operation of the to be terminated thread. I would still end up using Abort() on thread.

因此,我决定仅使用纯线程方法来实现它,而无需使用AsyncCallback.对您来说,这个thread.abort()正常且安全吗?

So i decided to just implement it with pure Thread approach, sans the AsyncCallback. Is this thread.abort() normal and safe to you?

public delegate DataSet LookupValuesDelegate(LookupTextEventArgs e);

internal delegate void PassDataSet(DataSet ds);

public class AutoCompleteBox : UserControl
{
   Thread _yarn = null;

   [System.ComponentModel.Category("Data")]
   public LookupValuesDelegate LookupValuesDelegate { set; get; }

   void DataSetCallback(DataSet ds)
   {
      if (this.InvokeRequired)
         this.Invoke(new PassDataSet(DataSetCallback), ds);
      else
      {
         // implements the appending of text on textbox here
      }
   }

   private void txt_TextChanged(object sender, EventArgs e)
   {
      if (_yarn != null) _yarn.Abort();

      _yarn = new Thread(
         new Mate
         {
            LookupValuesDelegate = this.LookupValuesDelegate,
            LookupTextEventArgs =
            new LookupTextEventArgs
            {
               RowOffset = offset,
               Filter = txt.Text
            },
            PassDataSet = this.DataSetCallback
         }.DoWork);

      _yarn.Start();
   }
}


internal class Mate
{
   internal LookupTextEventArgs LookupTextEventArgs = null;

   internal LookupValuesDelegate LookupValuesDelegate = null;

   internal PassDataSet PassDataSet = null;


   object o = new object();
   internal void DoWork()
   {
      lock (o)
      {
         // the actual code that queries the database
         var ds = LookupValuesDelegate(LookupTextEventArgs);
         PassDataSet(ds);
      }
   }
}

注释

当用户连续键入键时取消上一个线程的原因,不仅是为了防止文本的追加发生,而且是取消上一个网络往返,所以程序不会占用太多内存是由于网络连续运行造成的.

NOTES

The reason for cancelling the previous thread when the user type keys in succession, is not only to prevent the appending of text from happening, but also to cancel the previous network roundtrip, so the program won't be consuming too much memory resulting from successive network operation.

我担心是否要完全避免使用thread.Abort(),该程序可能会占用过多的内存.

I'm worried if I avoid thread.Abort() altogether, the program could consume too much memory.

这是不带线程的代码.使用计数器使用Abort():

here's the code without the thread.Abort(), using a counter:

internal delegate void PassDataSet(DataSet ds, int keyIndex);

public class AutoCompleteBox : UserControl
{
   [System.ComponentModel.Category("Data")]
   public LookupValuesDelegate LookupValuesDelegate { set; get; }

   static int _currentKeyIndex = 0;

   void DataSetCallback(DataSet ds, int keyIndex)
   {
      if (this.InvokeRequired)
         this.Invoke(new PassDataSet(DataSetCallback), ds, keyIndex);
      else
      {
         // ignore the returned DataSet
         if (keyIndex < _currentKeyIndex) return; 

         // implements the appending of text on textbox here...
      }
   }

   private void txt_TextChanged(object sender, EventArgs e)
   {
      Interlocked.Increment(ref _currentKeyIndex);

      var yarn = new Thread(
         new Mate
         {
            KeyIndex = _currentKeyIndex,
            LookupValuesDelegate = this.LookupValuesDelegate,
            LookupTextEventArgs =
            new LookupTextEventArgs
            {
               RowOffset = offset,
               Filter = txt.Text
            },
            PassDataSet = this.DataSetCallback
         }.DoWork);

      yarn.Start();
   }
}


internal class Mate
{
   internal int KeyIndex;
   internal LookupTextEventArgs LookupTextEventArgs = null;
   internal LookupValuesDelegate LookupValuesDelegate = null;
   internal PassDataSet PassDataSet = null;

   object o = new object();
   internal void DoWork()
   {
      lock (o)
      {
         // the actual code that queries the database
         var ds = LookupValuesDelegate(LookupTextEventArgs);
         PassDataSet(ds, KeyIndex);
      }
   }
}

推荐答案

不,它不安全. Thread.Abort()在大多数情况下是足够粗略的,但是在这种情况下,您的控件对委托回调中正在执行的操作没有任何(heh)控制.您不知道该应用程序的其余部分将保留在什么状态,并且当需要再次致电该委托人时,很可能会陷入痛苦的境地.

No, it is not safe. Thread.Abort() is sketchy enough at the best of times, but in this case your control has no (heh) control over what's being done in the delegate callback. You don't know what state the rest of the app will be left in, and may well find yourself in a world of hurt when the time comes to call the delegate again.

设置一个计时器.文本更改后稍等片刻,然后再调用委托.然后等待它返回,然后再次调用它.如果 that 慢,或者用户输入的 that 快,那么他们可能根本不希望自动完成.

Set up a timer. Wait a bit after the text change before calling the delegate. Then wait for it to return before calling it again. If it's that slow, or the user is typing that fast, then they probably don't expect autocomplete anyway.

您现在要为(可能)每个按键启动一个新线程.这不仅会降低性能,而且没有必要-如果用户没有暂停,他们很可能不在寻找该控件来完成输入的内容.

You're now launching a new thread for (potentially) every keypress. This is not only going to kill performance, it's unnecessary - if the user isn't pausing, they probably aren't looking for the control to complete what they're typing.

我之前提到过这个问题,但是 P爸爸说得更好:

I touched on this earlier, but P Daddy said it better:

您最好只是实施 一键式计时器,可能还有一个 半秒超时,并将其重置 每次击键.

You'd be better off just implementing a one-shot timer, with maybe a half-second timeout, and resetting it on each keystroke.

考虑一下:快速打字员可能会在第一个自动完成回调有机会完成之前创建一个线程分数,即使快速连接到快速数据库也是如此.但是,如果您将请求延迟到最后一次击键之后很短的时间,那么您就有更大的机会击中用户在其中键入了他们想要输入的所有内容(或他们所知道的全部内容)并且是 just 开始等待自动完成功能开始.延迟播放-半秒的时间可能适合不耐烦的触摸打字员,但是如果您的用户稍微放松一些...或者您的数据库慢一点...那么您可能会在2-3秒甚至更长的时间内获得更好的结果.但是,此技术最重要的部分是您reset the timer on every keystroke.

Think about it: a fast typist might create a score of threads before the first autocomplete callback has had a chance to finish, even with a fast connection to a fast database. But if you delay making the request until a short period of time after the last keystroke has elapsed, then you have a better chance of hitting that sweet spot where the user has typed all they want to (or all they know!) and is just starting to wait for autocomplete to kick in. Play with the delay - a half-second might be appropriate for impatient touch-typists, but if your users are a bit more relaxed... or your database is a bit more slow... then you may get better results with a 2-3 second delay, or even longer. The most important part of this technique though, is that you reset the timer on every keystroke.

并且除非您期望数据库请求实际上挂起,否则请不要试图允许多个并发请求.如果当前正在处理一个请求,请先等待该请求完成,再提出另一个请求.

And unless you expect database requests to actually hang, don't bother trying to allow multiple concurrent requests. If a request is currently in-progress, wait for it to complete before making another one.

这篇关于这个thread.abort()正常且安全吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆