当前位置: 首页 > 面试题库 >

这个thread.abort()是否正常且安全?

司徒宇
2023-03-14
问题内容

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

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

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

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

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);
      }
   }
}

笔记

在用户连续键入键时取消上一个线程的原因,不仅是为了防止文本的添加发生,而且还取消了上一个网络往返,因此该程序不会因为连续执行而消耗过多的内存。网络操作。

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

这是不带thread.Abort()的代码,使用一个计数器:

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()最好的时候是足够粗略的,但是在这种情况下,您的控件无法(委托)控制委托回调中的操作。您不知道该应用程序的其余部分将保留在什么状态,并且当需要再次致电该委托人时,很可能会陷入困境。

设置一个计时器。文本更改后稍等片刻,然后再html" target="_blank">调用委托。然后等待它返回,然后再次调用它。如果它 缓慢的,或用户打字
快的话,他们可能不希望自动完成反正。

关于更新的(无Abort())代码:

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

我之前提到过,但是P Daddy说的更好:

您最好只实现一个一键式定时器(可能会有一个半秒的超时),并在每次击键时将其重置。

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

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



 类似资料:
  • 我看到几乎每个人都在使用语句这里我们创建了一个类的实例,其类型为;如果我直接创建一个FirefoxDriver实例,作为

  • 问题内容: 我的Rails应用程序使用Devise进行身份验证。它有一个姐妹iOS应用程序,用户可以使用与该Web应用程序相同的凭据登录到iOS应用程序。所以我需要某种API进行身份验证。 这里有许多类似的问题指向本教程,但它似乎已过时,因为此模块已从Devise中删除,并且某些行会引发错误。(我使用的是Devise 3.2.2。)我曾尝试根据该教程(和本教程)推出自己的教程,但我对此并不百分百自

  • 如果不安装文本编辑程序或集成开发环境,是否有可能测试xdebug是否工作,即它是否可以调试php代码? phpinfo()中出现的唯一部分xdebug如下所示: 解析的其他. ini文件 /etc/php5/apache2/conf.d/mysql.ini, /etc/php5/apache2/conf.d/mysqli.ini, /etc/php5/apache2/conf.d/pdo.ini,

  • 我熟悉在一个账户和另一个账户之间转账时使用同步的并发示例,例如,两个账户的锁定是按账号顺序进行的,这样就不会发生死锁。 我想探索使用Reenter antReadWriteLock,因为在我看来,这将允许帐户对象的客户端进行并发读取,前提是没有客户端更新该对象。 我已经编写了代码并对其进行了测试,它似乎可以工作,但看起来有点难看,例如,Account类暴露其锁对象看起来有点奇怪,但它似乎必须这样做

  • 考虑以下程序: (编译器资源管理器) GCC和Clang的各种版本都可以接受它,但MSVC不能接受它,因为MSVC编译失败,出现错误消息 第一条错误消息向我暗示了ODR违规--但如果这个程序是格式不良的NDR,我需要帮助理解为什么会这样。我已经检查了标准草案中的temp.over.link,但我不相信我对它的解释是正确的。根据我的理解,程序是可以的,因为这些函数模板有不同的签名。 在不太可能的情况

  • 问题内容: 和 第二个代码产生了一个空指针异常,该怎么做才能使下一个等效? 问题答案: 我可以看到,如果players某个自定义java.lang.Iterable的get()实现的实现被破坏,或者至少以一种异常的方式(与的行为不同),就会发生这种情况。 除此之外,我唯一能想到的就是您未在代码中向我们展示的某些内容导致了某些错误。 如果执行此操作会怎样?