有一个TMemo控件,里面有N行数据。
我现在要写一个多线程的程序,假如有5个线程。
5个线程同时从TMemo读取数据。如:
TMemo有如下行:
123
456
789
234
345
567
线程T1读取了123
线程T2读取了456
线程T3读取了789
如何做到T1和T2不同时读取123。我现在是这样的,读取一行删一行,从后面向前读取。
比如567读取了,然后删掉。但是这样也会出现两个线程同时读取到了同一行。比如T1和T2同时都能读取到567。我现在用了TRTLCriticalSection,在读取TMemo先EnterCriticalSection读取完了再LeaveCriticalSection。
但是还是没用。有没有可能在一个线程操作TMemo控件的时候先把TMemo控件Lock,然后UnLock。哪位高手能赐教一二,写几段很简单的代码给小弟。分不多了,就剩下90分。

解决方案 »

  1.   

    定义一个行号变量p,开始p:=memo1.lines.count-1;
    每个线程取得控制权TRTLCriticalSection后,读取memo1.lines[p];并p:=p-1;再LeaveCriticalSection
      

  2.   

    是否有更好的办法呢?有没有可能在一个线程操作TMemo控件的时候先把TMemo控件Lock,然后UnLock。
      

  3.   

    使用TRTLCriticalSection了,其实就是完全控制tmemo了,为什么还要lock/unlock?如果一定要lock/unlock,可以使用TthreadList
      

  4.   

    声明一个变量默认值0,最大值为memo的count-1,超值为-1,然后对其赋值在一个函数里,该函数加锁,使用synchronize或者临界区均可
    所有线程要先取值然后到memo相应的行读取内容即可,因为取值函数加锁所以肯定正确,至于memo,不要随便改变其内容,因为这样肯定会影响其他线程
      

  5.   

    如果你对memo加锁,只能保证修改memo内容时不被线程读取到,但是一旦解锁还是有可能有多个线程同时读取其数据的
      

  6.   

    刚才写错了,synchronize不行,因为他是无参的procedure,要用临界区
      

  7.   


    如果每个线程都是加锁成功才能操作memo,就不会出现这种情况了
      

  8.   

    是的,他只是要读取memo,没必要都加锁去修改它例如这样
    先看下这个临界区怎么用
    http://www.anxue.net/tech/shiping/DELPHI/2010/0414/32056_2.html比如 首先你已经声明好全局变量num=0(可以是static的),还有cs是临界区,注意临界区不能声明在线程里,要在你的主程序里
    function getstr():string;
    var
    str:string;
     begin
      EnterCriticalSection(CS);
       if (num>memo1.lines.count-1)
       begin
         str:='';
         num:=-1;
       end
       else if (num<>-1)
        begin
          str:=memo1.lines[i];
          num=num+1;
        end;
      LeaveCriticalSection(CS);
      Result := str;
     end;
     
      

  9.   

    有段时间没用delphi了,代码手写的可能有错,Lz测试一下看看,另外因为没有修改memo的内容,所以不用对他进行lock,如果其内容可变的,则需要另外考虑了
      

  10.   

    这个临界区我昨天刚刚学完。小弟是delphi多线程新手。谢谢了。
      

  11.   

    还有刚才忘写了,临界区内要同try finally圈起来,以防万一
      

  12.   

    厄,其实我不过也是写过几个多线程程序而已,1年多没用delphi了,互相帮助吧,另外刚才写的例子里面的全局变量num绝对不要在其他地方随便读写,只能在有临界区的函数中进行操作
      

  13.   

    好像不行,我需要将Memo里面的全部内容一条一条的读取。
      while Form1.mmo1.Lines.Count <> Form1.ListBox1.Items.Count do
      begin
        str:= getstr;  //调用函数,这个函数就是上面你写的。
        if str <> '' then
          Form1.ListBox1.Items.Add(str);
      end;
      

  14.   

    没懂?为什么不行?memo1只是读取的话,上面的函数可以啊,虽然每次读取一条,但是他是递增的啊,你可以做个循环读取啊
      

  15.   

    比如num虽然不能随便读取,但是你可以写个循环读取嘛,一直到取出的str为''为止
      

  16.   

    把 if str <> '' then改成while
     
      

  17.   

    没错,我是做的循环读取。
    function FUN(p:Pointer):DWORD; stdcall;
    var
      str:string;
    begin
      while Form1.mmo1.Lines.Count <> Form1.ListBox1.Items.Count do
      begin
        str:= getstr;
        if str <> '' then
          Form1.ListBox1.Items.Add(str);
      end;
      Result:= 0;
    end;
    FUN就是循环读取。
    procedure TForm1.btn2Click(Sender: TObject);
    var 
      ID: DWORD;
    begin
      itemidex:= 0;
      CreateThread(nil, 0, @FUN, nil, 0, ID);
      CreateThread(nil, 0, @FUN, nil, 0, ID);
      CreateThread(nil, 0, @FUN, nil, 0, ID);
      CreateThread(nil, 0, @FUN, nil, 0, ID);
      CreateThread(nil, 0, @FUN, nil, 0, ID);
      CreateThread(nil, 0, @FUN, nil, 0, ID);
    end;
      

  18.   

    我试过了,这样读取出来的东西是不完全的。我假如我原来的数据是
    1
    2
    3
    4
    5
    6
    7
    8
    如果while str <> '' do
    则读取出来的数据如下:
    2
    4
    6
    8
      

  19.   

    看22L
    把你函数里面的if 和while换一下
    if (Form1.mmo1.Lines.Count <> Form1.ListBox1.Items.Count) then
       begin
         str:= getstr;
         while (str <> '')do
         begin
            Form1.ListBox1.Items.Add(str);
            str:= getstr;
          end;
         Result:= 0;
       end;
      

  20.   

    不好意思。搞错了,这里是我自己的代码写错了所以这样。
    这样写的话貌似读取出来会有问题。
        str:= getstr;
        while str <> '' do
          Form1.ListBox1.Items.Add(str);
      

  21.   

    你的需求是什么?
    每个线程,一旦获得控制权,就:顺序(还是逆序)读取整个lines?要不要删除?
      

  22.   

    晕死,我忘了说QQ,我QQ:858586182
      

  23.   

    楼主是否写过分割文件的程序,可以用Memo的行数除以你要创建的线程数(余数也好处理,就不细说了),每个线程就读取你所分配给它的那些行数据,就不会互相读取相同的数据了,你也不用读一行删一行了。不知能否帮到你。
      

  24.   

    临界是多线程内的同步方法
    临界中使用Memo1这些VCL控件,还是没用的.
    操作Memo控件的地方使用synchronize或SendMessage
    操作线程中全局变量的地方使用临界就行了
      

  25.   

    嗯,除了n个的工作线程,还有一个线程(主界面)会频繁操作vcl控件的,
    所以,工作线程操作vcl除了自己互斥外,还需要同步synchronize
      

  26.   

    我知道你的意思,我一开始想过,但是我现在必须要删除。我一开始是这样想的,如果Memo有9行,则线程T1读取1-3行,T2读取4-6行,T3读取剩余的。
    这样不会冲突,但是我如果要删除的话就不太好解决了。