Self-suspended flow in Delphi when it is not needed and safely resumes

This question includes Delphi and XE specifically designed to pause and resume. I read other posts, and until I found a similar use, so I'm going to go ahead and ask for a discussion.

Which identifier should know if there is a better way to pause a thread when it is not needed?

We have a Delphi class that we have used for many years, which basically represents the FIFO queue, which is associated with the stream process. The queue receives a data object in the main thread, and if the thread is paused, it will resume it.

As part of the thread. The process is running, the object is queued and processed in the thread. This is usually done to search the database.

At the end of the process, the property of the object is updated and marked as available for the main thread or transferred to another queue. The last (well, this is really the first) step of the Execute process is to check if there are more items in the queue. If it continues, otherwise it pauses.

The key is the only suspend action inside the Execute loop when it is complete, and only the resume during normal operations is called when a new item is queued. The exception is when the queue class finishes.

The resume function looks something like this.

process TthrdQueue.MyResume(); begin if Suspended then begin Sleep(1); //Allow thread to suspend if it is in the process of suspending Resume(); end; end; 

Execution is like this

 process TthrdQueue.Execute(); var Obj : TMyObject; begin inherited; FreeOnTerminate := true; while not terminated do begin if not Queue.Empty then begin Obj := Pop(); MyProcess(Obj); //Do work Obj.Ready := true; end else Suspend(); // No more Work end; //Queue clean up in Destructor end; 

The TthrdQueue Push procedure calls MyResume after adding another object to the stack. MyResume only calls Resume if the thread is paused.

On shutdown, we set the completion to true and call MyResume if it is paused.

+6
multithreading delphi resume
source share
3 answers

I would recommend the following implementation of TthrdQueue:

 type TthrdQueue = class(TThread) private FEvent: THandle; protected procedure Execute; override; public procedure MyResume; end; implementation procedure TthrdQueue.MyResume; begin SetEvent(FEvent); end; procedure TthrdQueue.Execute; begin FEvent:= CreateEvent(nil, False, // auto reset False, // initial state = not signaled nil); FreeOnTerminate := true; try while not Terminated do begin if not Queue.Empty then begin Obj := Pop(); MyProcess(Obj); //Do work Obj.Ready := true; end else WaitForSingleObject(FEvent, INFINITE); // No more Work end; finally CloseHandle(FEvent); end; end; 
+6
source share

Instead of pausing the thread, make it sleep. Lock it on some returned handle, and when the handle becomes a signal, the thread will wake up.

You have many options for pending objects, including events, mutex objects, semaphores, message queues, channels.

Suppose you decide to use an event. Make this an auto-reset event. When the queue is empty, call the WaitFor method. When something else fills the queue or wants to exit, call this SetEvent event.

I prefer to use the OS message queue function. I would replace your queue object with messages. Then write a standard GetMessage loop. When the queue is empty, it is automatically blocked to wait for a new message. Turn the completion request into just another message. (The TThread.Terminate method TThread.Terminate simply not a very useful function, as soon as you start doing something interesting with threads, because it is not virtual.)

+3
source share

There is a library that allows implementing a queue of producer-consumers in Delphi using variable conditions . This scenario is actually a case in point.

A classic example of a condition variables is the producer / consumer problem. One or more threads called manufacturers produce items and add them to the queue. Consumers (other topics) consume items by removing manufactured items from the queue.

+3
source share

All Articles