创建线程池实验

前几天,在工作线程完成任务后,通过在工作线程内执行 Suspend 将工作线程休眠,然后管理线程轮询线程池中的工作线程是否 Suspended 是否 = TRUE 要判断工作线程是否空闲。
但结果发现, 工作线程执行 Suspend 后,常常 Suspended = FALSE,搞得线程池中的工作线程全部假死。
只有另寻方法:用 Event 或 Mutex 通过去 WaitforSingleObejct 来实现工作线程休眠等待。
思路如下:
1. 在管理线程中为每个工作线程创建各自的Mutex,
2. 在工作线程完成工作后将 Mutex 置为无信号。
  并且 WaitForSingleObject(hMutex,INFINITE) 进入等待状态。
3. 管理线程在有任务时,查询各线程的 Mutex, 看看如果是无信号(表示正在休眠),马上分配任务给这个线程,并将属于这个线程的 Mutex 置为有信号,让它马上进入工作。

不知是否可行。

另外

在《Delphi 5 开发人员指南》中说到

引用:
提示 临界区与事件对象(比如互斥对象)的最大的区别是在性能上。临界区在没有线程冲突时,要用1 0 ~ 1 5个时间片,而事件对象由于涉及到系统内核要用400~600个时间片。

看了一早上的资料,发现只能用 Event 对像。
因为一个Thread已取得Mutex的所有权,而它呼叫WaitForSingleObject() n 次,则也要使用ReleaseMutex n次才能够将Mutex的拥有权放弃,而且,非Mutex拥有者呼叫ReleaseMutex也不会有任何作用。

 

destructor TThreadManager.Destroy;
begin
  Self.Terminate;
  inherited;
end;

procedure TThreadManager.Execute;
var
  n: Int64;
begin
  FreeOnTerminate := True;
  while not Terminated do
  begin
    Sleep(50);
    Inc(n);
  end;
end;

{中断线程}
procedure TfrmMainForm.btnStopClick(Sender: TObject);
begin
  {1 如果线程中有 FreeOnTerminate := True; 用
   ThreadManager.Terminate;
   *注: Terminate 并不直接终止线程, 只是将线程的 Terminated 置为 TRUE
  }

  {2. 如果线程中无 FreeOnTerminate := True;  且
  destructor TThreadManager.Destroy;
  begin
    Self.Terminate;
    inherited;
  end;
  用 FreeAndNil(ThreadManager);}
end;

 

FEvent: THandle;

FEvent := Windows.CreateEvent( nil,false, false, nil );

各参数的意义如下:
 
◇ 参数一:填上 nil 即可。
◇ 参数二:是否采用手动调整灯号。
◇ 参数三:灯号的起始状态,False 表示绿灯灭。
◇ 参数四:Event 名称, 对象名称相同的话,会指向同一个对
象,所以想要有两个Event对象,便要有两个不同的名称(这名
称以字符串来存.为NIL的话系统每次会自己创建一个不同的名字,就是被次创建的都是新的EVENT)。
◇ 传回值:Event handle。


实现: 在没任务时就阻塞工人线程, 不占用CPU资源, 有任务时绿灯唤醒:

池中的工人线程
代码:
procedure TThreadWorker.Execute;
var
  mTask: PTask;
begin
  while not Terminated do
  begin
    //一直休眠到 FEvent 被管理者线程亮灯为止....
    if FEvent > 0 then
      WaitForSingleObject(FEvent, INFINITE);
    //在管理线程中取任务
    FGetTask(mTask);

    //如果有任务
    if Assigned(mTask) then
    begin
      //处理任务....
      //DoSomething;

      mTask^.FCMD := '线程[' + IntToStr(FID) + ']任务:' + mTask^.FCMD;

      //将处理结果回写
      FAnswer(mTask);
    end;
  end;
end;
管理者类:
代码:
procedure TThreadManager.ManageTask(const AOption: TTaskOption;
  var VTask: PTask);
begin

  //进入临界区同步
  EnterCriticalSection(MANAGE_TASK_CS);
  try
    case AOption of
      eoRead: //取任务
        begin
          //如有任务, 取任务
          if FTaskPool.Count > 0 then
          begin
            VTask := PTask(FTaskPool[0]);
            FTaskPool.Delete(0);
          end
          else
            VTask := nil;

          //如没任务, 转红灯, 让工人们休息一会.
          if FTaskPool.Count = 0 then
            ResetEvent(FEvent);

        end;
      eoWrite: //添加任务
        begin
          FTaskPool.Add(VTask);
          VTask := nil;
          //亮绿灯, 唤醒工人, 周扒皮一下.
          SetEvent(FEvent);
        end;
    end; {case}
  finally
    { [修改者:谁变]try..finally保护,防卡线程进入监界面出现异常,
    无法执行离开监界区命令 }
    LeaveCriticalSection(MANAGE_TASK_CS);
  end;
end;
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值