主线程:
  TForm1 = class(TForm)
   .....
  public
    GridCs:TRTLCriticalSection;
    MyEvent:THandle;
  end;.....procedure TForm1.Button2Click(Sender: TObject);
begin
  TAAThread.Create(false);
end;procedure TForm1.Button6Click(Sender: TObject);
var i:integer;
begin
//  EnterCriticalSection(GridCs); //进入临界区
  waitforsingleobject(MyEvent,INFINITE);
  for i:=1 to 1000 do
  begin
    memo1.Lines.Add('i : '+inttostr(i));
  end;
//  LeaveCriticalSection(GridCs); //离开临界区
  SetEvent(MyEvent);
end;procedure TForm1.FormCreate(Sender: TObject);
begin
  InitializeCriticalSection(GridCs);//初始化临界区  MyEvent:=CreateEvent(0,false,false,0);
  setevent(MyEvent);
end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  DeleteCriticalSection(GridCs);//删除临界区  CloseHandle(MyEvent);
end;
子线程:
type
  TAAThread = class(TThread)
  private
    { Private declarations }
  protected
    FMessage: String;
    procedure LogMessage;
    procedure Execute; override;
  end;implementationuses unit1;procedure TAAThread.LogMessage;
begin
  Form1.Memo1.Lines.Add(FMessage );         
end;procedure TAAThread.Execute;
var i:integer;
begin
  waitforsingleobject(Form1.MyEvent,INFINITE);
  for i:=1 to 5000 do
  begin
    FMessage:='ii ------- : '+inttostr(i);
    Synchronize(LogMessage);
//    LogMessage;
  end;
  SetEvent(Form1.MyEvent);
end;如上代码。
我的操作是:按下Button2-->在子线程未打印完5000条之前,按下Button6 。
我想要的效果是:按下Button2-->在子线程未打印完5000条之前,按下Button6,但此时Memo1中继续打印子线程中的内容,子线程中内容打印完后,打印出Button6中的1000条内容 。
实际执行的效果:按下Button2-->在子线程未打印完5000条之前,按下Button6 -->程序死了(反白,不响应任何消息了)。我把 事件同步 改成用 临界区同步,效果一样?请问如何达到 我想要的效果?????

解决方案 »

  1.   

    waitforsingleobject(MyEvent,INFINITE);不要在进程中做无限期的等待才行.
      

  2.   

    Delphi有一个自带的多线程的例子,我记得是三个排序算法的,你可以看一下
      

  3.   

    procedure TForm1.Button6Click(Sender: TObject);
    var i:integer;
    begin
    //  EnterCriticalSection(GridCs); //进入临界区
      waitforsingleobject(MyEvent,INFINITE);
      for i:=1 to 1000 do
      begin
        memo1.Lines.Add('i : '+inttostr(i));
        Application.ProcessMessage;//添加这行
      end;
    //  LeaveCriticalSection(GridCs); //离开临界区
      SetEvent(MyEvent);
    end;
      

  4.   

    procedure TAAThread.Execute;
    var i:integer;
    begin
      waitforsingleobject(Form1.MyEvent,INFINITE);
      for i:=1 to 5000 do
      begin
        FMessage:='ii ------- : '+inttostr(i);
        Synchronize(LogMessage);
        Sleep(1);//添加这行
    //    LogMessage;
      end;
      SetEvent(Form1.MyEvent);
    end;
      

  5.   

    这样的话,现象是这样的:
    按下Button2-->在子线程未打印完5000条之前(假设打了X条),按下Button6-->Button6中的1000条全部打印出来-->打印 子线程中 剩下的 5000-X 条。
    和我要的不同啊。
      

  6.   

    to  wooden954
    按我的操作顺序,程序还是 死了(反白,不响应任何消息了)。 
      

  7.   

    我将button6中改为如下,其他还是如顶楼
    procedure TForm1.Button6Click(Sender: TObject);
    var i:integer;
    begin
    //  EnterCriticalSection(GridCs); //进入临界区
      waitforsingleobject(MyEvent,5000);
      for i:=1 to 1000 do
      begin
        memo1.Lines.Add('i : '+inttostr(i));
      end;
    //  LeaveCriticalSection(GridCs); //离开临界区
      SetEvent(MyEvent);
    end;
    则现象变为:
    按下Button2-->在子线程未打印完5000条之前(假设打了X条),按下Button6-->等5秒钟(这5秒钟内,程序没响应鼠标拖动等消息,5秒后 才执行了拖动等操作) ,Button6中的1000条全部打印出来-->打印 子线程中 剩下的 5000-X 条。
      

  8.   

    你是想要线程执行完再执行你的?
    BUTTON6 里线程对象.waitfor
      

  9.   

    真搞不懂你要做什么......
    waitforsingleobject在循环外等待EVENT的状态有啥用???
    最起码也是这样for i:=1 to xxx do
    begin
      waitforsingleobject(....,..);//等待事件信号
      if 事件信号被外界改写 then
      exit;
       memo1.Lines.Add('i : '+inttostr(i));end;
      

  10.   

    把exit换成你的处理过程,这里瞎写了一句:)
      

  11.   

    没有认真看, 答错了别骂我.哈哈.你可以开一个管理线程去做这个,当然你这个等待,就像一个循环一样,无限期前你得让一件事先做起来. 
    比如  :一个线程.
    WriteFile(....)..  做操作
    操作完了   ResetEvent
    管理线程必须是:  在他写做 WriteFile... 前 SetEvent 然后开始等待. 等到这个向量重置.
      

  12.   

    你的打印任务是线性的,即打完5000,再打1000。所以你的子线程应该是设计为接受打印任务。主线程应该是给这个子线程下达任务,所以打印1000,也应该给子线程做,不应该在主线程做(在主线程做,你又要保持任务是线性的,得waitfor,主线程当然会挂起来)。
    你可以透过消息,将打印任务,以消息的形式通知子线程,如:
       while getmessage(....) do
       begin
         取得消息参数带的打印信息
          判断打印
       end;
    或者透过变量,如
       while not terminated do
      begin
        if 变量 then
       ...
      end;
      

  13.   

    如果你不想让你的主线程死掉,你可以这样
    waitforsingleobject(MyEvent,INFINITE);把这个换了
    while true do
    begin
      case waitforsingleobject(MyEvent,1000) of  //等待1秒,或者等待成功或者超时退出
        WAIT_OBJECT_0: Break;
        WAIT_TIMEOUT: application.processmessage;
      else
        Break;
      end;
    end;for i:=1 to 1000 do 
    ......
      

  14.   

    感谢 楼上各位!此问题产生的原因有点明白了。
    我问这个问题的原因是:我的程序里 主线程 和 子线程 都会对窗口里的一个 StringGrid 进行操作(添加一行、删除一行 修改等等),所以我想通过线程同步 把 StringGrid保护起来。
    因此就想到了:在子线程操作StringGrid时,主线程也想操作StringGrid,于是就有了楼顶我比较极端的问题。
    通过楼上各位的帮助,现在想来,我以下观点是否比较合理、正确、方便、有效?:
    1、主线程 和 子线程 都要操作 主窗口中的 StringGrid ,那最好是把 “操作StringGrid的动作” 集中到一个线程里?其中用消息的方式 将要 插入、删除的信息发给那个线程。
    2、如果 主线程不操作StringGrid,只有 子线程1、子线程2、子线程3..... 操作StringGrid的话,是否就可以不用把“操作StringGrid的动作”集中到一个线程里??各子线程随便怎么操作,只要做好线程同步就行。以上两点我理解的对不?
      

  15.   

    对于我18楼说的,如果把对StringGrid的操作 集中 到一个线程里的话,就不必用到EnterCriticalSection--LeaveCriticalSection、  waitforsingleobject--SetEvent 这些了吧?
      

  16.   

    如果你的插入操作是随机的(也就是说没有顺序的要求,谁都可以在任意时间插入数据,但一次插入是不可打断的),那么你使用线程中提供的那个同步函数(syn什么的,忘了,呵呵)就行。
    如果你的插入是有序的,那么,你就需要使用线程同步的知识了。
    所谓的有序,就是说在B插入之前,A必须先插入。
      

  17.   

    StringGrid 是线程不安全的,你对它的操作,都应该让主线程去操作,而不是子线程
      

  18.   


    呵呵,确实,楼主没必要用线程来做,顺序处理好了。
    楼主可能想在写程序的时候,顺便学习下线程吧。
    没用过事件信号,我只用过变量来判断的,如MyEvent:Boolean;
      

  19.   

    waitforsingleobject本来就是阻塞方式,界面没有相应很正常。