http://www.paradicesoftware.com/blog/2014/02/dont-use-suspend-and-resume-but-dont-poll-either/

Don’t use Suspend and Resume, but don’t poll either.

Category: Code, Good coding guidelines / Tag: event, FPC, queue, resume, sleep, suspend, thread, worker /Add Comment
 

So, using thread Suspend and Resume functionality is deprecated in Delphi, Freepascal, and even Windows MSDN itself warns against using it for synchronization.

There are good reasons for trying to kill this paradigm: suspending and resuming other threads from the one you’re currently on is a deadlock waiting to happen, and it’s typically not supported at all in OS’es other that Windows. The only circumstance where it’s needed is to start execution of a thread that was initially created suspended (to allow additional initialization to take place). This is still supported and a new command has been added to FPC/Delphi called “TThread.Start” which implements this.

However, a number of people are confused about how to correctly re-implement their “worker thread” without using suspend/resume; and some of the advice given out hasn’t been that great, either.

Let’s say you have a worker thread which normally remains suspended. When the main thread wants it to do something, it pushes some parameters somewhere and then resumes the thread. When the thread is complete, it suspends itself. (note: critical sections or other access protection on the “work to do” data needs to be here too, but is removed for clarity):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{the worker thread's execution}
procedure TMyThread.Execute;
begin
   repeat
      if (work_to_do) then
         //...do_some_work...
      else
         Suspend;
   until Terminated;
end;
 
{called from the main thread:}
procedure TMyThread.QueueWork(details);
begin
   //...add_work_details...
   if Suspended then
      Resume;
end;

Although the particular example above still works, now’s a good time to go ahead and clean this up so that you’re not depending on deprecated functions.

Here’s where we get to the inspiration for today’s post. The suggested ‘clean up’ is often implemented using polling. Let’s take something I saw suggested on stackoverflow as a replacement for the above:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
procedure TMyThread.Execute;
begin
   repeat
      if (work_to_do) then
         //...do_some_work...
      else
         Sleep(10);
   until Terminated;
end;
 
procedure TMyThread.QueueWork(details);
begin
   //...add_work_details...
end;

Yuck! What’s the problem with this design? It’s not particularly “busy”, since it sleeps all the time, but there are issues. Firstly: if the thread is idle, it can be 10-milliseconds before it gets around to realizing there’s any work to do. Depending on your application that may or may not be a big deal, but it’s not exactly elegant.

Secondly (and this is the bigger one for me), this thread is going to eat 200 context switches per second (2 per 10ms), whether busy or not. A far worse design than the original! Context switches aren’t free! If we assume 50,000 nanoseconds per context switch (0.05ms), which seems a reasonable finding, 200 of them per second just ate 1% of the total capacity of a processor core, to achieve nothing except wait. There’s a better solution, right?

Use Event Objects

Fortunately, there are better ways than Sleeping and Polling. The best replacement for the above scenario is just to deploy an event. Events can be “signalled” or “nonsignalled”, and you can let the operating system know “hey, I’m waiting for this event”. It will then go away and not waste any more cycles on you until the event is signalled. Brilliant! How do you do this? Well, it depends on your language:

  • Win32 itself exposes event handles (see CreateEvent) which can be waited on with the WaitFor family of calls
  • Freepascal provides a TEventObject, which encapsulates the Win32 (or other OS equivalent) functionality
  • Delphi uses TEvent, which does the same thing
  • C# uses System.Threading.ManualResetEvent (and related)

Here’s how to rewrite the above handler using a waitevent, so it consumes no CPU cycles until an event arrives. (I’ll use the FPC mechanism, but they’re functionally identical in all the other languages).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
constructor TMyThread.Create;
begin
   //...normal initialization stuff...
   mEvent := TEventObject.Create(nil,true,false,'');
end;
 
{the worker thread's execution}
procedure TMyThread.Execute;
begin
   repeat
      mEvent.WaitFor(INFINITE);
      mEvent.ResetEvent;
      if (work_to_do) then
         //...do_some_work...
 until Terminated;
end;
 
{called from the main thread:}
procedure TMyThread.QueueWork(details);
begin
 //...add_work_details...
 mEvent.SetEvent;
end;

Presto! Thread will happily wait until a new piece of work comes in, without consuming any CPU cycles at all, and it will respond immediately once there’s something to do. The only caveat on this design? The only way out of the .WaitFor() call is for the event to be signalled, so you also need to account for this when you want to terminate the thread for good. (note that FPC’s TThread.Terminate isn’t virtual, so we have to cast to TThread to get the correct call):

1
2
3
4
5
6
7
8
procedure TMyThread.Terminate;
begin
   // Base Terminate method (to set Terminated=true)
   TThread(self).Terminate;
 
   // Signal event to wake up the thread
   mEvent.SetEvent;
end;

Sorted!

Don’t use Suspend and Resume, but don’t poll either.的更多相关文章

  1. 被废弃的 Thread.stop, Thread.suspend, Thread.resume 和Runtime.runFinalizersOnExit

    最近学习多线程的知识,看到API里说这些方法被废弃了,就查了一下原因 Thread.stop 这个方法会解除被加锁的对象的锁,因而可能造成这些对象处于不一致的状态,而且这个方法造成的ThreadDea ...

  2. JAVA多线程suspend()、resume()和wait()、notify()的区别

    suspend() 和 resume() 方法:两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的 resume() 被调用,才能使得线程重新进入可执行状态.典型 ...

  3. Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated ?

    Thread.stop, Thread.suspend, Thread.resume被标记为废弃的方法.在查看JDK的文档时,提到了下面的参考文章,先是英文版,接着是中文翻译. Why is Thre ...

  4. 通过SIMPLE_DEV_PM_OPS定义suspend和resume函数【转】

    本文转载自:https://blog.csdn.net/tiantao2012/article/details/77851782 通过SIMPLE_DEV_PM_OPS 定义这个驱动的suspend和 ...

  5. Linux的系统suspend和resume

    参考: www.wowotech.net/linux_kenrel/suspend_and_resume.htmlwww.wowotech.net/linux_kenrel/pm_interface. ...

  6. Java 学习笔记之 Suspend和Resume

    Suspend和Resume: Suspend和Resume使用方法: 以下例子证明了线程确实被暂停了,而且还可以恢复成运行状态. public class SuspendResumeThread e ...

  7. 使用 suspend 和 resume 暂停和恢复线程

    suspend 和 resume 的使用 在 Thread 类中有这样两个方法:suspend 和 resume,这两个方法是成对出现的. suspend() 方法的作用是将一个线程挂起(暂停), r ...

  8. Java中的线程Thread方法之---suspend()和resume()

    前篇说到了Thread中的join方法,这一篇我们就来介绍一下suspend()和resume()方法,从字面意义上可以了解到这两个方法是一对的,suspend()方法就是将一个线程挂起(暂停),re ...

  9. C#Thread的方法、Start()、Sleep(int)、Abort()、Suspend()、Resume()

    Thread类有几个至关重要的方法 Start():启动线程: Sleep(int):静态方法,暂停当前线程指定的毫秒数: Abort():通常使用该方法来终止一个线程: Suspend():该方法并 ...

随机推荐

  1. html元素中class属性值多个空格分格

    问题: 比如 <div class="alert alert-info"> 回答: 同时指定了多个CSS样式,这里面的alert-info还可以换成alert-warn ...

  2. 将错误日志记录在txt文本里

    引言 对于已经部署的系统一旦出错对于我们开发人员来说是比较痛苦的事情,因为我们不能跟踪到错误信息,不能 很快的定位到我们的错误位置在哪,这时候如果能像开发环境一样记录一些堆栈信息就可以了,这时候我们就 ...

  3. hdu 5492 Find a path(dp+少量数学)2015 ACM/ICPC Asia Regional Hefei Online

    题意: 给出一个n*m的地图,要求从左上角(0, 0)走到右下角(n-1, m-1). 地图中每个格子中有一个值.然后根据这些值求出一个最小值. 这个最小值要这么求—— 这是我们从起点走到终点的路径, ...

  4. JDBC数据源(DataSource)的简单实现

    数据源技术是Java操作数据库的一个很关键技术,流行的持久化框架都离不开数据源的应用.   数据源提供了一种简单获取数据库连接的方式,并能在内部通过一个池的机制来复用数据库连接,这样就大大减少创建数据 ...

  5. 第一个UI脚本--python+selenium

    之前一直是用java+selenium做自动化测试的,最近因为工作需要,需要用pyhton+selenium去实现,于是就赶驴上架,熟悉了一下python的语法和脚本的编写过程,下面是一个简单的脚本, ...

  6. 【转】linux之tune2fs命令

    转自:http://czmmiao.iteye.com/blog/1749232 tune2fs简介 tune2fs是调整和查看ext2/ext3文件系统的文件系统参数,Windows下面如果出现意外 ...

  7. 自动抓取java堆栈

    参数1 进程名字,参数2 最大线程数 例: pid为8888,达到1000个线程时自动抓取堆栈信息 ./autojstack.sh 8888 1000 & #!/bin/bashfileNam ...

  8. 在 Asp.NET MVC 中使用 SignalR 实现推送功能

    一,简介Signal 是微软支持的一个运行在 Dot NET 平台上的 html websocket 框架.它出现的主要目的是实现服务器主动推送(Push)消息到客户端页面,这样客户端就不必重新发送请 ...

  9. Hive常用命令

    本位为转载,原地址为:http://www.cnblogs.com/BlueBreeze/p/4232421.html #创建新表 hive> CREATE TABLE t_hive (a in ...

  10. 9段高效率开发PHP程序的代码

    php是世界上最好的语言 在php网站开发中,大家都希望能够快速的进行程序开发,如果有能直接使用的代码片段,提高开发效率,那将是起飞的感觉.今天由杭州php工程师送出福利来了,以下9段高效率开发PHP ...