(3)超时服务的终止

客户端的不当使用或ServerObject的设计不良,一次服务会常时间执行或长生不死,这常时间占据服务器的CPU和资源,影响服务器对别的客户的服务,因此,需要设定一个服务超时时间,如1分钟、10分钟,超过这个时间的调用就会被强制终止。

如何终止?当然是终止服务的线程,但千万不要使用TerminateThread这个API,它太暴力,使线程没有机会执行清理工作,外面也不知道这个线程已经被终止,典型的现象就是客户端收不到任何错误,并一直等下去...

如何完全终止线程,有人说要靠线程内部检查某个值,然后满足条件就自己终止,话需不错,假设线程都是我们在服务器自己创建的,因此可以加入这样的代码,但是,如果线程中的某一条语句本身要很长时间呢,这个线程还是要等到这个语句执行完毕才有机会来检查超时条件,但这个时候可能已经超时好多好多了,所以这个方法也不行。

唯一的方法是使用GetThreadContext和SetThreadContext,挂起线程,截获线程的快照,在线程中插入一段代码(如Abort),然后恢复线程执行。但有时候一次不会成功,因为你插入的代码可能恰好在try...except里面,没有引起异常,所以可能要多来几次。

procedure InjectProc_AbortThread;
begin
//举发异常,使正常释放资源
  Abort;
//  Raise Exception.Create(S_CallTimeout);
//  finally
//  EndThread(STATUS_TIMEOUT);
//  end;
end;

procedure SafeAbortThread(AThreadHandle:THandle);
var
  vThreadContext:TContext;
  pStack:PDWORD;
  vWaitResult:Cardinal;
  vSuspendCount:Cardinal;
  vEnjected:Boolean;
  vWaitTime:integer;
begin
//在工作线程插入Abort指令,可能这个指令恰好被try except拦掉,
//所以不停的测试
//等待其执行完毕,不会马上停止,有时对数据库的访问要等近1分钟才出现异常
  Sleep(0);
  vWaitResult:=Windows.WaitForSingleObject(AThreadHandle,0);
  repeat
    case vWaitResult of
      WAIT_FAILED:
        begin
          tmErrorLog.ErrorLog.Log(SysErrorMessage(Windows.GetLastError),nil,nil);
          break;
        end;
      WAIT_OBJECT_0:
        begin
          break;
        end;
      else
        begin
          vEnjected:=false;
          Windows.SuspendThread(AThreadHandle);
          try
            vThreadContext.ContextFlags:=CONTEXT_FULL;
            if Windows.GetThreadContext(AThreadHandle,vThreadContext) then
            begin
              if (Cardinal(vThreadContext.Eip)<$70000000) then
              begin
                pStack:=Pointer(vThreadContext.Esp);
                Dec(pStack);
                if not IsBadWritePtr(pStack,4) then
                begin
                  vThreadContext.Esp:=DWORD(pStack);
                  pStack^:=vThreadContext.Eip;
                  vThreadContext.Eip:=DWORD(@InjectProc_AbortThread);
                  vThreadContext.ContextFlags:=CONTEXT_CONTROL;
                  vEnjected:=SetThreadContext(AThreadHandle,vThreadContext);
                end;
              end;
            end
            else break;
          finally
            repeat
              vSuspendCount:=Windows.ResumeThread(AThreadHandle);
            until (vSuspendCount<=1) or (vSuspendCount=$FFFFFFFF);
          end;
      //交出本线程执行时间
          Sleep(0);
      //检查工作线程执行情况
          if vEnjected then vWaitTime:=100
          else vWaitTime:=0;
          vWaitResult:=Windows.WaitForSingleObject(AThreadHandle,vWaitTime);
        end;
    end;
  until false;
end;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

火星牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值