小弟做了个类似于选号的程序,思路是这样的:
在一个数据库(名字叫Code)中存大量的号码,一个字段是 Num 放号码,一个字段是 Used 做为Boolean型的标志位,初始时都是False,代码所有号码都没被用过。
然后在程序中设置一个 Flag 是Boolean型的标志位,控制循环,初始是True。
然后在窗体上放两个按钮一个 Start 一个 Stop,Start点击后打开数据库开始循环显示号码(没用过的),Stop点击后停止循环,窗口中显示的会停在一个号码上,然后打开数据库查找到显示的那个号码,把它的Used字段值改为True,代表这个号被用过了。一开始没用线程做,直接用的一个While(Flag),点击Stop按钮后就把Flag改为False希望把无限循环停下来,但是实际上点了Start按钮后程序就一直飞快的在那里无限循环,根本响应不了点击Stop按钮的操作。后来没办法现学现卖用了WinAPI的CreateThread函数来创建线程处理无限循环,这样才能响应点击Stop按钮的操作。但是问题来了,线程中的无限循环大致是这样的:With Query_Code do
  begin
    Close;
    SQL.Clear;
    SQL.ADD('Select Num from Code where Used = "False"');
    Open;
    First;
    while (Flag) do
      begin
        Edit1.Text := FieldByName('Num').AsString;   //在窗体上显示当前的号码
         Edit1.Refresh;
        if EOF
        then First;    //如果到了数据集的最后就返回到第一个
        else Next;     //如果不是最后一个就向后移动
      end;
    Close;
  end;然后Stop按钮的代码大致如下:Flag := False;
With Query_Code do
  begin
    Close;
    SQL.Clear;
    SQL.ADD('Select * from Code where Num = ' + Edit1.Text);
    Open;
    Edit;
    FieldValues['Used'] := True;
    Post;
    Close;
  end;
开始跑线程后,点Stop就会报错说无法对只读的数据库进行写操作。我估计是虽然Flag置了False使窗口上显示的号码停了下来,但是仿佛线程根本没结束没关闭,数据库还开着,所以Stop里对数据库的Post操作非法,尽管用了Edit过程想把数据库置为可编辑状态。请问我该如何确定线程已经彻底关闭,数据库被释放出来?
或者说我该使用一种什么手段来有效的停止线程,好象有看到说用Flag这种标志位在线程里用着是有什么问题。我的线程没用TThread类,直接用的WinAPI。第一次尝试线程的编程,太多东西不熟悉了。
或者不用线程能解决那种无限循环后程序无法响应点击按钮的问题吗?

解决方案 »

  1.   

    所有的数据库操作都放在线程中
    修改数据库用update语句实现
    线程循环中添加个Sleep(10)
    stop按钮只修改flag值
      

  2.   

    注意
       把所有的实现代码全放到一个线程里stop按钮只修改一个标志位 Stopped:=True;在线程里判断Stopped是否为True 是的话执行你的操作并关闭数据库另外
      在线程中操作VCL需要用Synchronize(your procedure)的方式
      

  3.   

    不用线程也可以在循环中加入
    Application.ProcessMessages;
    if Stopped then
       结束
    else
    begin
      //your code
    end;Stop按钮只修改一个变量 不要进行其他操作
      

  4.   

    昨天发了问题后用baidu搜索了下,知道了3楼兄弟提到的方法,今天已经把程序改成了非线程版的,运行没问题,程序先做出来准备好,元旦起码有个东西能交差。然后明天开始试着用1、2楼兄弟介绍的方法用线程的方式再实现程序。多一种尝试多会点东西,而且线程这东西应该是必须掌握的。正好拿这个程序练练手玩会线程的一些技巧。谢谢了~~
      

  5.   

    egin
     if ExportFileInfo.isFilesUp then
      begin
        StringList:=ExportFileInfo.getUpFileList; //获取导出文件目录下的文件列表
        while StringList.Count>0 do
        begin
          i:=StringList.Count-1;
          clientSockThread:=TClientSockThread.create();//ServerInfo
          clientSockThread.upFileName:=StringList.Strings[i];  //所要上传的文件名称:1.txt
          //clientSockThread.TExportInfo:=exportInfo;
          filePath:= ExportInfo.ExportPath+'\export\'+StringList.Strings[i];
          DeleteFile(pchar(filePath));
          StringList:=ExportFileInfo.getUpFileList; //重新获取文件列表
          sleep(200);
        end;
        StringList.Free;
      end;
    end;