Delphi:线程作业的线程列表-排队

Delphi:线程作业的线程列表-排队,delphi,multithreading,queue,Delphi,Multithreading,Queue,我有一些基于TThreads的操作。现在我需要创建包含要完成的作业列表的线程,然后在前一个任务完成后立即触发每个任务。。。我该怎么写呢?我不能允许线程同时运行,因为可能要执行10000多个操作。 很难找到TEvent和其他同步对象的文档化示例。。。 希望我能在这里找到一些帮助 提前感谢,, michal假设您有一个线程可以执行其他线程,比如WorkerThread 在WorkerThread中,您可以将要调用的线程放在一个TThread数组中,一个TThreadList,TList,基本上是您更

我有一些基于TThreads的操作。现在我需要创建包含要完成的作业列表的线程,然后在前一个任务完成后立即触发每个任务。。。我该怎么写呢?我不能允许线程同时运行,因为可能要执行10000多个操作。 很难找到TEvent和其他同步对象的文档化示例。。。 希望我能在这里找到一些帮助

提前感谢,,
michal

假设您有一个线程可以执行其他线程,比如WorkerThread

在WorkerThread中,您可以将要调用的线程放在一个TThread数组中,一个TThreadList,TList,基本上是您更喜欢的

然后在for循环中启动它们中的每一个。现在,因为您不希望它们同时运行,所以有两种方法等待正在运行的线程,或者使用一些标志并侦听线程的OnTerminate事件,当触发该事件时设置标志,或者使用

WaitForSingleObject(Thread.Handle, INFINITE);

我刚刚实现了一些非常类似的东西

我想你想要的是一个线程池系统

您有一个线程池,其中包含一定数量的线程(将同时执行的最大项目数)。然后创建一个工作单元对象,并将其放入队列中。每个工作线程获取第一个可用的排队工作单元并执行它。完成后,工作线程将等待,直到队列中有更多的工作单元


这种方法的优点是,您可以轻松控制并发操作的最大数量,并且不必为每个操作创建和丢弃线程(这很昂贵).

我不完全理解您的问题,也不真正理解使用多线程然后序列化执行的意义…但您可以这样做:

 JobList : TList <TThread>;
 ...
 JobList.Add (TMyCustomThread.Create (True));  // Create suspended
 JobList.Add (TMyOtherThread.Create (True));   // Create suspended
 ...
 for Thread in JobList do
   begin
   Thread.Start;
   Thread.WaitFor;
   end;
JobList:TList;
...
JobList.Add(TMyCustomThread.Create(True));//创建挂起的
JobList.Add(TMyOtherThread.Create(True));//创建挂起的
...
对于作业列表中的线程,请执行以下操作
开始
线程。开始;
Thread.WaitFor;
结束;
这将执行每个线程,然后等待线程完成后再执行下一个线程

示例代码假定您使用D2009或更高版本(您在问题中没有指定),并且您已经在挂起状态下创建了线程。如果使用较旧的Delphi版本,则必须调用
Resume
而不是
Start
,并且必须使用简单的
TList
或数组替换通用的
TList


请注意示例代码中的内存泄漏。

不要将操作基于线程。这是错误的设计。相反,您应该为您的操作创建一个基类,它公开了一个执行该操作的方法。编写子类来实现具体操作。不要对线程上下文做任何假设,总是使用关键部分或类似的同步对象来保护对共享资源的访问。更重要的是,尽量避免共享资源,或者至少尝试将共享资源设为只读,这样就不需要锁定


有了这种设计,就可以通过直接调用operation方法在VCL线程中执行每个操作,使用
TThread
子类在其自己的线程中执行一个操作(您现在似乎拥有的),或者在线程池上调度所有操作。池中的线程数可以在运行时调整,以匹配操作的性质(处理器绑定或I/O绑定)和系统拥有的处理器内核数。回答您的问题:甚至可以通过强制池使用单个线程来完全序列化操作。基本上,您可以完全更改操作的执行方式,而无需进行任何更改。

您应该看看。它使工作线程非常简单,您基本上只需为它添加一个任务即可;每一个都会在前一个任务完成后立即启动,并且库允许您轻松地将状态消息等传递回主线程以进行UI更新。

泛型集合TQueue可以用作单个作业对象的容器

然后,工作线程将拾取(“提取”)第一个作业并执行它,然后继续,直到队列为空-然后必须暂停,直到将另一个作业添加到队列并继续


在添加新作业时,您需要实现对队列的线程安全访问。

当多个线程不能同时运行时,使用多个线程有什么意义?基本上,线程中封装的代码可以通过用户操作直接执行,并且是线程化的,以避免GUI冻结。现在我需要执行几百次,但我无法将代码移出线程,因为每个请求的执行必须留在应用程序中。这就是为什么我需要一个接一个地执行线程的原因。您应该始终指出您所指的是哪个版本的Delphi,因为这可能会有所不同。例如,D2010有mjustin在下面提到的TQueue,而D7没有。我的答案中的OmniThreadLibrary支持D2007及以上版本,因此它对D5没有任何好处。对,我的错,对不起。不幸的是,我仍然使用D7。。。我将尝试JVCL线程。应该避免等待
INFINITE
,并在有睡眠的循环中等待。通过这种方式,你可以检测到线程是否崩溃/运行太慢,并处理它,而不是永远玩弄你的虚拟拇指?为什么不传递一个不同于
INFINITE
的值呢?这确实会同时运行多个线程,如果我理解正确,OP希望避免这种情况。据我理解,OP希望避免同时运行10000个线程(相当合理!)。线程池/作业队列系统允许控制同时运行的线程数。