procedure TMyThread.Procedure0;   
begin
  if form1.CheckBox1.Checked then
  XXX
end;
在我的线程里这样直接访问没问题,但是多次运行后就会有问题,或者有时候会莫名其妙的问题.然后朋友说用SendMessage取Checkbox的状态于是我这样 SendMessage(form1.CheckBox1.Handle,BM_GETCHECK,0,0)) ,这代码没问题吧?如果不一样大家是怎么写的?这里我问题又来了,为什么CheckBox.Checked不能直接访问,
而CheckBox.Handle可以直接访问呢?Sendmessage要Checkbox的Handle还有就是哪些控件可以直接访问和操作呢?

解决方案 »

  1.   

    vcl最好都不要直接访问,用上同步,或者发消息
      

  2.   


    总结一下Windows常用的几种线程同步技术。
    1.Critical Sections(临界段),源代码中如果有不能由两个或两个以上线程同时执行的部分,可以用临界段来使这部分的代码执行串行化。它只能在一个独立的进程或一个独立的应用程序中使用。使用方法如下:
    //在窗体创建中
    InitializeCriticalSection(Critical1)
    //在窗体销毁中
    DeleteCriticalSection(Critical1)
    //在线程中
    EnterCriticalSection(Critical1)
    ……保护的代码
    LeaveCriticalSection(Critical1)2.Mutex(互斥对象),是用于串行化访问资源的全局对象。我们首先设置互斥对象,然后访问资源,结果释放互斥对象。在设置互斥对象时,如果另一个线程(或进程)试图设置相同的互斥对象,该线程将会停下来,直方前一个线程(或进程)释放该互斥对象为止。注意它可以由不同应用程序共享。使用方法如下:
    //在窗体创建中
    hMutex:=CreateMutex(nilfalsenil)
    //在窗体销毁中
    CloseHandle(hMutex)
    //在线程中
    WaitForSingleobject(hMutexINFINITE)
    ……保护的代码
    ReleaseMutex(hMutex)3.Semaphore(信号量),它与互斥对象相似,但它可以计数。例如可以允许一个给定资源同时同时被三个线程访问。其实Mutex就是最大计数为一的Semaphore。使用方法如下:
    //在窗体创建中
    hSemaphore:=CreateSemaphore(nillInitialCountlMaximumCountlpName)
    //在窗体销毁中
    CloseHandle(hSemaphore)
    //在线程中
    WaitForSingleobject(hSemaphoreINFINITE)
    ……保护的代码
    ReleaseSemaphore(hSemaphore lReleaseCount lpPreviousCount)4.还可以使用Delphi中的TcriticalSection这个VCL对象,它的定义在Syncobjs.pas中。当你开发多线程应用时,并且多个线程同时访问一个共享资源或数据时,你需要考虑线程同步的问题了。5.CreateEvent也可以用于同步delphi中多线程同步的一些方法[转]当有多个线程的时候,经常需要去同步这些线程以访问同一个数据或资源。例如,假设有一个程序,其中一个线程用于把文件读到内存,而另一个线程用于统计文件中的字符数。当然,在把整个文件调入内存之前,统计它的计数是没有意义的。但是,由于每个操作都有自己的线程,操作系统会把两个线程当作是互不相干的任务分别执行,这样就可能在没有把整个文件装入内存时统计字数。为解决此问题,你必须使两个线程同步工作。 楼主看这里 http://www.enbaja.com/index.php/Topic/view/id-6084
      

  3.   


    没人知道吗???我这不是线程同步问题,是操作和访问VCL问题,我的VCL主线程是不会去动它的
      

  4.   

    Delphi 中, 绝大部份的VCL控件(就是可以拖到窗体上的控件)都是非线程安全的. 如果你在子线程中操作VCL控件时会和VCL主线程产生未知的访问冲突, 使程序产生异常甚至崩溃. 除非这个VCL控件有lock与Unlock的功能则可以在子线程中直接访问. 如:
    procedure TMyThread.Procedure0;   
    begin
        Form1.Canvas.Lock ;
        Form1.Canvas.TextOut(10, 10, '这样是安全的') ;
        form1.Canvas.Unlock ;  
    end;
    小弟就知道这么多了. 希望对你有点帮助.
      

  5.   

    SendMessage(form1.CheckBox1.Handle,BM_GETCHECK,0,0)) ;这样应该也是不安全的, 只是你运气好, 没有激发冲突.  你可以在线程的create事件中, 把checkbox1.handle 斌值给线程内部的一的个整型变量.   或者用同步方式取得check状态.
      

  6.   

    没错,“vcl可视控件不是线程安全的”
    这句话的意思是:这些控件的代码并没有考虑同时有多个线程对他进行调用执行的情况。
    当现实中出现多个线程对同一个控件的方法进行调用的时候,情况可能会很混乱,不可预知。
    因此约定的规则是:对于界面可视控件的访问,都是由主线程负责。其他的线程若要访问,就要利用TThread的Synchronize方法将他放到主线程中访问。
      

  7.   

    我现在要在线程里判断form1.CheckBox1.Checked的状态,我应该怎么去判断我不想用全局变量的方法,也不想用 把checkbox1.handle赋给线程变量的方法,这些都不理想高手们不都是sendmessage么,句柄都是怎么来的.这个checkbox只有子线程才访问的,不存在冲突问题
      

  8.   

    比如: 当用户拖动窗体时即会访问VCL控件的. 另外窗口也在不断的刷新着.  所以checkbox不光是子线程才访问他. 下面是一个比较另类的访问方法. 
      Tsub = class(TThread)
      private
        Fck: Boolean ;
        procedure SynGetCkBoxstatus ;
      protected
        procedure Execute ; override ;
      public
        function GetCkBoxStatus: Boolean ;
      end;var
      Form1: TForm1;implementation{$R *.dfm}{ Tsub }procedure Tsub.Execute;
    begin
      inherited;
      if GetCkBoxStatus then
      begin
        //........
      end;
    end;function Tsub.GetCkBoxStatus: Boolean;
    begin
      Synchronize(SynGetCkBoxstatus); //异步的方式执行.
      Result := Fck ;
    end;procedure Tsub.SynGetCkBoxstatus;
    begin
      Fck := Form1.CheckBox1.Checked ;
    end;