如何传递或使Tthread可访问的公共变量或字段?

时间:2011-07-12 13:24:40

标签: multithreading mono delphi-prism tthread

我正在使用Delphi Prism为Mono编写和构建我的软件。所以,我决定我的串行通信将由一个线程处理。由于除非为项目启用全局变量选项,否则严格禁止全局变量,因此我决定遵循Delphi Prism约定。那么,那么如何传递或使线程可以访问公共变量或字段呢?

这是我的测试主体代码:

MainForm = partial class(System.Windows.Forms.Form)

  private
    method SignalBtn_Click(sender: System.Object; e: System.EventArgs);
    method CommBtn_Click(sender: System.Object; e: System.EventArgs);
    method button1_Click(sender: System.Object; e: System.EventArgs);
    method button2_Click(sender: System.Object; e: System.EventArgs);
    method button4_Click(sender: System.Object; e: System.EventArgs);
    method button5_Click(sender: System.Object; e: System.EventArgs);
    method MainForm_Load(sender: System.Object; e: System.EventArgs); 
    method ShutdownBtn_Click(sender: System.Object; e: System.EventArgs);
    method MySerialData(sender: System.Object; e:SerialDataReceivedEventArgs);
    method LoginBtn_Click(sender: System.Object; e: System.EventArgs);
  protected
    method Dispose(disposing: Boolean); override;
  public
    RX:Array[0..5] of byte;
    TX:Array[0..6] of byte;
    serialPort1:System.IO.Ports.SerialPort;
    thr:Thread;
    stoploop:Boolean;
    mcommand:Byte;
    thechannel:Integer;
    constructor;
    method FillTable;
  end;

这是用于串行通信的线程:

  ThreadComm = class(MainForm)
  public
    class procedure mythread; static;
  end;

以下是ThreadComm的运行方式:

class procedure ThreadComm.mythread;
begin
    while true do
    begin
        TX[0]:=$FF;
        TX[1]:=$01;
        TX[2]:=$01;
        TX[3]:=$04;
        TX[4]:=$A2;
        TX[5]:=(TX[2] xor TX[3] xor TX[4]);

        SerialPort1.Write(TX,0,6);
        while SerialPort1.BytesToWrite>0 do;
        Thread.Sleep(100);

        if (stoploop) then
            break;
    end;
end;

每次编译代码时,都会引发30条左右的类似错误消息,说明如下:

无法在没有实例引用的情况下调用实例成员“SerialPort1”

我知道错误意味着什么,但解决它的唯一方法是创建一个mainform实例。如果这样做,那么它将不是与主程序实例相同的实例。如果是这种情况,那么当您需要访问其字段或公共变量时,您将不得不一直创建新的mainform实例。正确?

class method Program.Main(args: array of string);
begin
  Application.EnableVisualStyles();
  Application.SetCompatibleTextRenderingDefault(false);
  Application.ThreadException += OnThreadException;
  **using lMainForm := new MainForm do
    Application.Run(lMainForm);**
end;

我想在线程中使用所有变量,它们恰好位于mainform公共区域内。

由于

2 个答案:

答案 0 :(得分:1)

将您的主题所需的内容作为参数传递给其构造函数。将对这些对象的引用存储为线程类中的字段。在线程运行时使用它们。

并且不要让你的线程类成为主窗体的后代。这是没有意义的。如果您的线程需要访问整个表单,则将MainForm引用传递给线程的构造函数。但是,如果您的所有线程需求都是串行端口对象,那么只需传递它,而不是整个表单。

不要创建MainForm的其他实例。这将创造更多的形式;它不会让您访问真实主表单的字段值。

答案 1 :(得分:1)

您的线程过程(class procedure mythread; static;)似乎是“静态”或“类”,而您要访问的字段是MainForm 实例的常规字段。这不起作用,因为只有一个procedure mythread,但可能有多个MainForm个实例。虽然在实践中可能只有一个MainForm实例,编译器不知道。

您应首先从该过程中删除class前缀和static sufix,以使其成为可以读取实例字段的常规实例过程。即使这还不够,因为你从你的MainForm 派生,我假设你创建了一个ThreadCom的新实例并启动线程:一旦你使方法成为常规实例方法代码将编译,但结果不会是您期望的结果,因为您将访问不同的 MainForm实例的成员。

解决方案:

  • 使mythread程序成为MainForm的实例方法。它将获得对所有必填字段的访问权限并从适当的实例访问它们!
  • 按照Rob的建议:创建一个新类, not 派生自MainForm,在构造函数中传递MainForm的实例,通过线程过程传递它。您(再次)需要避免使用静态/类字段和过程,因为这些字段和过程无法链接到一个 MainForm实例。