Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 在Delphi中自挂起线程时';不需要,安全恢复_Multithreading_Delphi_Resume_Suspend - Fatal编程技术网

Multithreading 在Delphi中自挂起线程时';不需要,安全恢复

Multithreading 在Delphi中自挂起线程时';不需要,安全恢复,multithreading,delphi,resume,suspend,Multithreading,Delphi,Resume,Suspend,这个问题涉及到Delphi和XE,它们特别反对Suspend和Resume。我读过其他帖子,到目前为止还没有发现类似的用法,所以我将继续讨论 我想知道的是,有没有更好的方法在不需要线程时暂停它 我们有一个已经使用多年的Delphi类,它基本上是一个FIFO队列,与线程化进程关联。队列在主线程上接受一个数据对象,如果线程被挂起,它将恢复它 作为线程执行过程的一部分,对象将弹出队列并在线程上处理。通常这是为了进行数据库查找 在进程结束时,对象的属性将被更新并标记为可供主线程使用或传递给另一个队列。执

这个问题涉及到Delphi和XE,它们特别反对Suspend和Resume。我读过其他帖子,到目前为止还没有发现类似的用法,所以我将继续讨论

我想知道的是,有没有更好的方法在不需要线程时暂停它

我们有一个已经使用多年的Delphi类,它基本上是一个FIFO队列,与线程化进程关联。队列在主线程上接受一个数据对象,如果线程被挂起,它将恢复它

作为线程执行过程的一部分,对象将弹出队列并在线程上处理。通常这是为了进行数据库查找

在进程结束时,对象的属性将被更新并标记为可供主线程使用或传递给另一个队列。执行过程的最后一步(实际上是第一步)是检查队列中是否还有其他项。如果有,它将继续,否则它将暂停自己

当执行循环完成时,它们是唯一的挂起操作,而在正常操作期间,当队列中放置新项时,将调用唯一的恢复。队列类终止时会出现异常

resume函数看起来像这样

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;
execute看起来与此类似

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;  
TthrdQueue Push例程在堆栈中添加另一个对象后调用MyResume。MyResume仅在线程挂起时调用Resume


关闭时,我们将terminate设置为true,如果MyResume被挂起,则调用它。

我建议使用以下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;

不要暂停线程,而是让它休眠。使它阻塞在某个可等待句柄上,当该句柄发出信号时,线程将被唤醒

可等待对象有许多选项,包括事件、互斥对象、信号量、消息队列和管道

假设您选择使用一个事件。使其成为自动重置事件。当队列为空时,调用事件的
WaitFor
方法。当其他东西填充队列或想要退出时,让它调用事件的方法


我更喜欢的技术是使用OS消息队列。我将用消息替换您的队列对象。然后,编写一个标准的
GetMessage
循环。当队列为空时,它将自动阻塞以等待新消息。将终止请求转换为另一条消息。(一旦您开始对线程执行任何有趣的操作,那么
TThread.Terminate
方法就不是一个非常有用的函数,因为它不是虚拟的。)

有一个库允许在中实现生产者-消费者队列。这个场景实际上就是所讨论的示例

条件的经典例子 变量是生产者/消费者 问题一个或多个线程称为 生产者生产并添加项目 排队。使用者(其他线程) 通过删除已生成的 队列中的项目


我不是专家,但我会简单地使用Sleep(250)或SignalObjectAndWait(参见msdn)进行更精确的控制。他提到他在Delphi XE上,所以他已经可以访问Generics.Collections单元中的TThreadedQueue泛型类。TThreadedQueue是一个FIFO队列,具有在推送和弹出时同步线程的能力。我们的库中仍然支持很多Delphi7代码。但我将在未来的研究中关注TThreadedQueue。我喜欢给定的解决方案,因为它可以轻松地更新我们现有的代码。这看起来是一个很好的解决方案,但是你打算什么时候调用MyResume?队列会这样做吗?什么时候?它如何知道要唤醒哪些线程?或者,当一个项目添加到队列的后面时,您是否会立即唤醒所有正在睡眠的线程。我明白您使用Windows支持队列的意思。我们一直在使用的是很多现有的代码,现在已经足够好了。但我会在以后的工作中仔细研究它,我很喜欢它的自动性。非常感谢。