程序中根据条件创建了数目不定的多个线程通过SOCKET传输远端计算机的信息,请问如何在主线程中随时及时的停止这些线程哪?(如果在创建的线程中加入退出条件,则这些线程非同时退出,拖延时间较久)谢谢!

解决方案 »

  1.   

    回复人: happyzsl(学习) ( ) 信誉:100  2002-12-04 15:04:00  得分:0 
      用Threads来保存线程列表
     回复人: aquadp(阿凯) ( ) 信誉:100  2002-12-04 15:05:00  得分:0 
      好像是用线程的terminate方法和free吧,试试
     回复人: happyzsl(学习) ( ) 信誉:100  2002-12-04 15:06:00  得分:0 
      是TThreadList不是Threads,呵呵
     回复人: zhxk32899559(小爪)( ) 信誉:100  2002-12-04 15:22:00得分:0 
      如何保存啊,能举个例子吗?
     回复人: moudy(勇士) ( ) 信誉:100  2002-12-04 16:06:00  得分:0 
      我的偶像。
     回复人: moudy(勇士) ( ) 信誉:100  2002-12-04 16:07:00  得分:0 
      发错了,sorry。
     回复人: happyzsl(学习) ( ) 信誉:100  2002-12-04 16:08:00  得分:0 
      mylist := TThreadList.Create;
      mylist.Add(thread1); 
      mylist.Add(thread2);
      ...
      我没实际用过,你试试看,怎样说一下
     回复人: moudy(勇士) ( ) 信誉:100  2002-12-04 16:26:00  得分:0 
      既然来了就随便说两句吧!不对别砸我。
      先把线程缓存起来。在onterminate事件中。
      var  cache:TThreadlist;
      procedure Tmythread.terminate(sender:Tobject);
      begin
       cache.add(self); 
      end;
      程序需要线程时,调用getthread().看看就知道作用。
      function getThread:Tthread;
      begin
        with cache.locklist do
        begin
          if count then
          begin
            result:=TThread(items[0]);
            delete(0);
          end
          else
            result:=TmyThread.create(true);
        end;
        cache.unlocklist;
      end;
      终止时除掉线程。
    procedure ApplicationDeactivate(sender:Tobject);
    var i:integer;
    begin
    with cache.locklist do 
    begin
     for i:=count-1  do 
    begin
     item[i].free;
     delete[i];
    end;
    end;
    cache.unlocklist;
    end;ok 了。
     回复人: zhxk32899559(小爪) ( ) 信誉:100  2002-12-06 08:47:00  得分:0 
      多谢勇士出手,不过请问为什么在Tmythread.terminate中将线程加入cache哪?
     回复人: zhxk32899559(小爪) ( ) 信誉:100  2002-12-06 08:52:00  得分:0 
      补充一下,所创建的数目不定的多个线程除非满足一定条件,否则一直在循环执行,并不是一次执行完线程就终止。
      

  2.   

    问题是怎么用啊,上面moudy(勇士)说的我编译不过啊,另外也没看明白。大家请回答详细些好吗?谢谢。
      

  3.   

    俺好像记得有个api函数是专名杀api函数的,可惜我记不住名字了
    好像是killThread..你自己找找吧
      

  4.   

    TerminateThread(ThreadHandle,0)
    试下!
      

  5.   

    //可以用Event来试试
      TMyThread = class(TThread)
      private
        FWaker: THandle;
        FTimeout: Integer;
      protected
        procedure Execute; override;
      public
        property Waker: THandle read FWaker write FWaker;
        property Timeout: Integer read FTimeout write FTimeout;        constructor Create(CreateSuspended: Boolean);
        destructor Destroy; override;
      end;constructor TMyThread.Create(CreateSuspended: Boolean);
    begin
      FWaker := CreateEvent(nil, True, False, nil);
      inherited Create(CreateSuspended);
    end;destructor TMyThread.Destroy;
    begin
      CloseHandle(FWaker);
      inherited;
    end;procedure TMyThread.Execute;
    begin
      while not Terminated do
      begin
        //do something
        WaitForSingleObject(FWaker, FTimeout);
      end;
    end;//主程序里可以更改MyThread.Waker状态来唤醒线程,如:
      MyThread.Terminate;
      SetEvent(MyThread.Waker);
      

  6.   

    勇士的方法,是用来做一个Thread Pool,线程池。它的GetThread,是从池中检取一个已经Terminated的(空闲的)Thread(如
    果没有空闲的就新建一个)来应用。当然,这些Thread的功能任务是一样的。当任务完成时,Thread自动将自己放回池中,所以TMyThread.OnTerminate中调用cache.add(self),以便下一次使用。这个方法可以节省创建Thread和结束Thread的时间。
    如果要在主线程中随时及时地停止这些线程,可以在你的线程的Execute代码中的等待资源的地方,尽量使用WaitForMultipleObjects(Ex),以同时等待主线程的退出信号,一旦等到的是主线程的退出信号,就立即善后,然后调用Terminate;这样,你的主线程可以在需要停止这些线程的时候设置退出信号。
      

  7.   

    多谢诸位帮忙,我正在查WaitForMultipleObjects的用法,
    alphax(尽我所知帮助你吧) :你好
    勇士说的那种方法不能及时地停止线程以并安全的释放资源吗?
    它给的代码编译不过cache.locklis.items[i]没有free方法。
      

  8.   

    //勇士说的那种方法不能及时地停止线程以并安全的释放资源吗?
    勇士说的那种方法和能不能及时停止线程并安全地释放资源这个问题没有关系,
    她只是一种线程缓冲池实现方法,目的只是节省创建和撤销线程的时间。
    至于能不能及时停止线程并安全释放资源要看你的Thread的实现
    //它给的代码编译不过cache.locklis.items[i]没有free方法。
    勇士可能是临时写给你的,自己没有运行过,不过它的大致意思是,仅供参考:====================================================//检取一个空闲的工作线程对象
    function RetriveFreeThread: TThread;//等待所有工作线程中止
    procedure TerminateWorkingThreads;implementationvar
      ThreadPool :TThreadlist;type
      TMyThread = class(TThread)
      protected
        procedure DoTerminate; override;
        //procedure Execute; override; //这里自己完成
      end;procedure TMyThread.DoTerminate;
    begin
      ThreadPool.Add(Self); //放回缓冲池
    end;function RetriveFreeThread: TThread;
    begin
      with ThreadPool.LockList do
      try
        if Count > 0 then
        begin
          Result := TThread(Items[0]);
          Delete(0);
        end
        else
          Result := TMyThread.Create;
      finally
        ThreadPool.UnlockList;
      end;
    end;procedure TerminateWorkingThreads;
    var
      I: Integer;
    begin
      with ThreadPool.LockList do
      try
        for I := 0 to Count-1 do
          TThread(Items[0]).Terminate;
          //虽然调用了Terminate,但是线程们并不一定都立即中止,因为它们还在工作
          //或者在等待什么,甚至再无限等待,所以最好就是给它们发信号(使用Win32的
          //事件对象)而不只是简单的调用Terminate,而工作线程在有需要无限等待
          //(比如监听客户的连接请求)时,应该同时等待主线程的中止信号。
          //具体的你可以参考CreateEvent, WaitForMultipleObjects等函数的帮助    for I := 0 to Count-1 do
          TThread(Items[0]).WaitFor;
      finally
        ThreadPool.UnlockList;
      end;
    end;procedure FreeThreads;
    begin
      with ThreadPool.LockList do
      try
        while Count > 0 do
        begin
          TThread(ThreadPool.Items[0]).Free;
          Delete(0);
        end;
      finally
        ThreadPool.UnlockList;
      end;
    end;initialization
      ThreadList := TThreadList.Create;finalization
      if ThreadList <> nil then
      begin
        FreeThreads;
        ThreadList.Free;
      end;end.
      

  9.   

    对不起,搞错了!
    勇士说的那种方法不能及时地停止线程以并安全的释放资源吗?
    勇士说的那种方法和能不能及时停止线程并安全地释放资源这个问题没有关系,
    她只是一种线程缓冲池实现方法,目的只是节省创建和撤销线程的时间。
    至于能不能及时停止线程并安全释放资源要看你的Thread的实现
    //它给的代码编译不过cache.locklis.items[i]没有free方法。
    勇士可能是临时写给你的,自己没有运行过,不过它的大致意思是,仅供参考:====================================================//检取一个空闲的工作线程对象
    function RetriveFreeThread: TThread;//等待所有工作线程中止
    procedure TerminateWorkingThreads;implementationvar
      FreeThreadPool, WorkingThreads :TThreadlist;type
      TMyThread = class(TThread)
      protected
        procedure DoTerminate; override;    procedure Execute; override; //这里自己完成
      end;procedure TMyThread.DoTerminate;
    begin
      with WorkingThreads.LockList do
      try
        WorkingThreads.Remove(Self);
      finally
        WorkingThreads.UnlockList;
      end;  FreeThreadPool.Add(Self); //放回缓冲池
    end;procedure TMyThread.Execute;
    begin
      with WorkingThreads.LockList do
      try
        Add(Self);
      finally
        WorkingThreads.UnLockList;
      end;
    end;function RetriveFreeThread: TThread;
    begin
      with FreeThreadPool.LockList do
      try
        if Count > 0 then
        begin
          Result := TThread(Items[0]);
          Delete(0);
        end
        else
          Result := TMyThread.Create;
      finally
        FreeThreadPool.UnlockList;
      end;
    end;procedure TerminateWorkingThreads;
    var
      I: Integer;
    begin
      with WorkingThreads.LockList do
      try
        for I := 0 to Count-1 do
          TThread(Items[I]).Terminate;
          //虽然调用了Terminate,但是线程们并不一定都立即中止,因为它们还在工作
          //或者在等待什么,甚至再无限等待,所以最好就是给它们发信号(使用Win32的
          //事件对象)而不只是简单的调用Terminate,而工作线程在有需要无限等待
          //(比如监听客户的连接请求)时,应该同时等待主线程的中止信号。
          //具体的你可以参考CreateEvent, WaitForMultipleObjects等函数的帮助    while Count > 0 do
          TThread(Items[0]).WaitFor;
      finally
        WorkingThreads.UnlockList;
      end;
    end;procedure FreeThreads;
    begin
      with FreeThreadPool.LockList do
      try
        while Count > 0 do
        begin
          TThread(ThreadPool.Items[0]).Free;
          Delete(0);
        end;
      finally
        FreeThreadPool.UnlockList;
      end;
    end;initialization
      FreeThreadList := TThreadList.Create;
      WorkingThreads := TThreadList.Create;finalization
      if FreeThreadList <> nil then
      begin
        FreeThreads;
        FreeThreadList.Free;
      end;  WorkingThreads.Free;  end.
      

  10.   

    在需要的地方 ThreadName.Terminate ;
      

  11.   

    alphax(尽我所知帮助你吧(02.10)) :阁下真是人如其名啊,十分感谢阁下这么详尽的指点。我是个新手,我去查查CreateEvent, WaitForMultipleObjects的资料,如不得要领或许还要麻烦阁下。
      

  12.   

    alphax:
      你好!
      我查了一些CreateEnent,与WaitForMultipleObjects的资料,可是由于功力较浅,只能一知半解,也没能找到简单易懂的代码(好多这方面的程序是涉及到通信的)。
      能不能给举一个简单的例子哪?谢谢!
      

  13.   

    你的这个帖子我很早看到了,只是看到那么多人回就没回了,没想到还在!其实使用WaitForMultipleObjects是使用互斥元,它和使用临界区Critical Section都主要实现线程同步的。不知道你搞清楚你的线程退出耗时的原因。
    一般使用Socket网络通讯的时候,会使用一种组塞模式,当某个套接字阻塞的时候
    使用互斥元,或者临界区都是无效的,因为线程已经处于挂起状态。这个时候只有强制关闭该套接字才能使线程激活而达到退出的目的。如果说你的退出耗时不是由于这个原因导致的,那么你就该看看你线程循环怎么写的,尽量是循环一次所耗时间缩短,每次循环判断主线程的退出标志。这个时候可以使用互斥元或者临界区来访问这个标志,不过,既然只有你的主线程会修改这个标志,那么使用互斥元或者临界区都是不必要的,反而浪费时间。
      

  14.   

    zwjchina(蒲石):
       你好,多谢你的帮助,我给你发了条消息,不知你收到了没有?
      

  15.   

    zwjchina(蒲石)已经说得很清楚了,下面是一个简单的例子。该例子是关于
    重叠I/O模式下的命名管道的例子(不好意思,实在是想不到别的不是关于
    通讯的例子,而且因为不完整所以我不可能测试过),里面有CreateEvent
    和WaitForMultipleObjects的用例:
    type
      TWorkingThread = class(TThread)
      private
        fTerminateEvent: THandle;
      protected
        procedure Execute; override;
      public
        constructor Create(aTerminateEvent: THandle);
      end;const
      PipeName = '\\.\pipe\YourPipeNameHere';constructor TWorkingThread.Create(
        aTerminateEvent: THandle      //主线程创建的、传递给工作线程的中止信号对象
      );
    begin
      inherited Create(True);
      fTerminateEvent := aTerminateEvent;
    end;procedure TWorkingThread.Execute;
    var
      hPipe: THandle;
      Overlap: TOverlapped;
      WhatToWait: array[1..2] of THandle;
    begin
      //创建命名管道
      hPipe := CreateNamedPipe(PChar(PipeName),
          PIPE_ACCESS_DUPLEX                //双工模式
          or FILE_FLAG_OVERLAPPED,          //异步I/O模式
          PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE,       //消息制
          4,                                //最多4个实例,你也只应创建4个TWorkingThread的实例
          1024,
          1024,
          1000,
          nil);  if hPipe = 0 then
      begin
        ReturnValue := -1;
        Exit;
      end;  FillChar(Overlap, SizeOf(Overlap), 0);
      try
        //创建连接完成信号
        Overlap.hEvent := CreateEvent(nil,
            True,                             //手动复位方式
            False,                            //初始为没有信号
            nil);    if Overlap.hEvent = 0 then
        begin
          ReturnValue := -2;
          Abort;
        end;    while not Terminated do
        begin
          //异步调用连接
          if not ConnectNamedPipe(hPipe, @Overlap)
          and GetLastError <> ERROR_IO_PENDING then
          begin
            ReturnValue := -3;
            Abort;
          end;      WhatToWait[1] := Overlap.hEvent;
          WhatToWait[2] := fTerminateEvent;      //等待连接完成或者主线程的中止信号到达
          case WaitForMultipleObjects(Length(WhatToWait), @WhatToWait,
                False, INFINITE) of
            WAIT_FAILED: //等待失败
              RaiseLastOSError;        WAIT_OBJECT_0:
            begin
              //等到的是客户的连接完成信号
              ResetEvent(Overlap.hEvent); //复位信号,这样你可以使用这个信号对象在后面的
                                          //重叠I/O中          ...                         //可以在这里完成与客户的交互(读写管道)
              ...
            end;        WAIT_OBJECT_0 + 1:
            begin
              //等到的是主线程中止监听连接的信号,马上中止
              Terminate;
            end;
          end;
        end;
      finally
        //释放核心对象
        if hPipe <> 0 then
          CloseHandle(hPipe);
        if Overlap.hEvent <> 0 then
          CloseHandle(Overlap.hEvent);
      end;
    end;
      

  16.   

    十分感谢用心回答我问题的同行们,尤其是alphax(尽我所知帮助你吧(02.10)),让我学到很多东西,问题虽然还未解决,但我想大家已将问题说的很明白了,余下的该我自己多看看书,学学基础的东西了来深刻理解大家给出的建议,我应该结贴了:)