我觉得你要用 Monitor 来监视你共享的操作对象

解决方案 »

  1.   

    这个问题在微软msdn上讲的很清楚了你看看异步的相关内容吧要用到Control.Invoke方法.
      

  2.   

    我使用了this.BeginInvoke(new InvokeDelegate(ShowDataInTextBox),o);
    问题依旧
      

  3.   

    this.BeginInvoke(...)有没有EndInvoke()?
      

  4.   

    我是这么处理的:有一个utils类,实现接受/发送的代码,需要更新UI的时候,触发一个事件(先定义好delegate)。UI的类中类似于这样的代码:myutils.BeginReceiving += new ReceivingHandler(OnBeginReceiving);
    ...不要直接操作界面。如果你的UI有多个,那么在一个统一的点上(如mainform上),对这些UI中的对于utils的事件响应,统一在这里登记处理。
      

  5.   

    非常感谢各位的关注!我的那个接收数据的线程是使用事件来触发的。
    就如:
    myutils.BeginReceiving += new ReceivingHandler(OnBeginReceiving);
    我收到一条数据后,就立刻回发一条,以表明接收到数据了。
    希望 juqiang1975 和 reformer能说得详细一些,迷惑中...
      

  6.   

    比如说你的主界面form叫做mainform,上面有两个自己的UI控件,假设叫:MasterUI和DetailUI。
    你的数据处理类,叫做DBUtils。DBUtils的处理方法可能是这样:public class DBUtils{
    public void MyMethod(){
    // 开始处理
    if(null != BeginReceiving)BeginReceiving(this,new EventArgs()); // 循环什么咚咚
    for(int i=0;i<MAX;i++){
    // 通知外面,处理到第i个数据了
    if(null != Receiving)Receiving(this,new YourEventArgs(i));
    } // 循环结束了
    if(null != EndReceiving)EndReceiving(this,new EventArgs());
    }
    }然后在你的两个UI中,可能都需要这个Utils的这个方法,那么,代码可能是这样:public class MasterUI : SomeControl{
    public void MasterUI(DBUtils utils){
    utils = new DBUtils();
    utils.BeginReceiving += new EventHandler(OnBeginReceiving);
    utils.Receiving += new MyReceivingEventHandler(OnReceiving);
    utils.EndReceiving += new EventHandler(OnEndReceiving);
    } private void OnBeginReceiving(object sender, EventArgs e){
    // 这段代码你即可以上浮到mainform上,形如下面这行,也可以在这里直接处理。
    // if(null != BeginReceiving)BeginReceiving(this,new EventArgs());
    messageToDrawing = "Begin receiving...";
    Invalidate();
    } // 其他代码类似
    }我就是juqiang1975,那是我的马甲。
      

  7.   

    改为使用this.Invoke()应该没问题,我一直都是这样使用的。
      

  8.   

    thx a lot!那个通讯类首先开启一个线程,等待进行接收数据:
    // Start the receiver thread.
    this.rxThread = new Thread(new ThreadStart(ReceiveThread));
    this.rxThread.Name = "COMReceiver";
    this.rxThread.Priority = ThreadPriority.AboveNormal;
    this.rxThread.Start();// Wait for receive thread to start.
    this.recvrEvent.WaitOne(500, false);然后在这个ReceiveThread方法里面进行事件的触发:
    private void ReceiveThread()
    {
    // Create locals.
    uint firedEvent = 0;
            //...
            
    // Create thread signal (initial state is non-signaled). 
    AutoResetEvent signal = new AutoResetEvent(false);
            //... // Signal the main thread that 
    // the receive thread is started.
    this.recvrEvent.Set(); try
    {
    while(true) 
    {
    // Arm the event monitoring mask.
    if(this.events.Set(this.port.Handle, Win32Events.EV_DEFAULT))
    {
    // 等待事件发生
    this.events.Wait(this.port.Handle, signal); // Get mask of fired events.
    firedEvent = this.events.GetMask;
                                    //.....
    // Receive event 接收数据的事件--接收到一个字节就触发
    if(((firedEvent & Win32Events.EV_RXCHAR) != 0) && (this.immediate))
    {
    do 
    {
    nBytes = 0;
                                                    //从串口读取数据
    if(this.port.Read(buf, 1, out nBytes, this.rxOvr.MemPtr)) 
    {
    if(nBytes == 1)
                                                                    //调用执行处理接收到数据的方法  
    this.OnRxChar(buf);
                                                                    
    }
    } while(nBytes > 0);
                                            //...
    }
             }
    }
              }
      catch(Exception e)
    {
                //....
    }
    }
      

  9.   

    to  juqiang(方枪枪(正在修炼伤心小箭)) :
    我正是像你这样的方式写的。Control.Invalidate()是必须调用的么?
      

  10.   

    我最近也碰到了这样的问题,但是我并没有通过调用Control.Invalidate()也能实现对界面元素进行修改啊!
      

  11.   

    我用了Control.Invalidate()也还是没用。up
      

  12.   

    不可能数据太频繁的原因,我用VB.net做过一个能同时接收多个TCP/IP连接通道的数据的程序,接收程序在多个线程中,刷新界面由接收线程触发界面窗口的事件,在事件中调用Me.Invoke(delegateMethod,objParam),不会死啊,而且做过同时连接100多个客户端,并自动频繁发送数据,也不会出问题啊
      

  13.   

    to leogon(leogon) :
    是啊,我也是如你说的那样的做法。
    接收数据的线程就是触发事件的,在这个事件里面处理接收到的数据,并且显示到界面上的。能给我一些代码么?
      

  14.   

    你接收到数据后,在界面上响应的代码,在哪里?是this.OnRxChar吗?外面UI的handler代码怎么写的?
      

  15.   

    正是OnRxChar里面写的。
    UI:private WithEvents Func;//处理发生事件的结构体//初始化端口
    private void InitSerial()
    {
    this.Func = new WithEvents();

    this.Func.Error   = new StrnFunc(this.OnError);
    this.Func.RxChar  = new ByteFunc(this.OnRecvI);//OnRxChar
    this.Func.CtsSig  = new BoolFunc(this.OnCts);
    this.Func.DsrSig  = new BoolFunc(this.OnDsr);
    this.Func.RlsdSig = new BoolFunc(this.OnRlsd);
    this.Func.RingSig = new BoolFunc(this.OnRing);
    this.Port = new SerialPort(this.Func);
             if(this.Port.IsOpen == false)
                  this.Port.Open(this.PortIndex);//打开串口
                  ...
    }
    /// <summary>
    /// 当接收到数据时所作的处理
    /// </summary>
    internal void OnRecvI(byte[] b)
    {   //我在这里处理接收到的字节:b
       //将收到的b显示到界面上
    }
      

  16.   

    奇怪,为什么我没碰到这个问题,后台线程里面是可以直接更新主界面数据的,下面的程序就可正常运行,不会出现楼主说的情况private Thread x;
    static void Main() 
    {
    Application.Run(new Form1());
    }
    void thread_show()
    {
    while(true)
    {
    textBox1.AppendText(System.DateTime.Now.ToString());
    textBox1.ScrollToCaret();
    }
    }
    private void button1_Click(object sender, System.EventArgs e)
    {
    x = new Thread(new ThreadStart(thread_show));
    x.Start();
    }
    private void button2_Click(object sender, System.EventArgs e)
    {
    x.Abort();
    }
      

  17.   

    在串口类里面:// Delegate class declarations.
    public delegate void VoidFunc();
    public delegate void BoolFunc(bool b);
    public delegate void StrnFunc(string s);
    public delegate void ByteFunc(byte[] b);/// <summary>
    /// This structure contains one delegate method for each override event
    /// method in the serial port base class. Each delegate provides a hook
    /// that can be used by any application that wishes to connect to the
    /// asynchronous OnXXX methods.
    /// </summary>
    public struct WithEvents
    {
    public VoidFunc Break;
    public VoidFunc TxDone;
    public StrnFunc Error;
    public ByteFunc RxChar;
    public BoolFunc CtsSig;
    public BoolFunc DsrSig;
    public BoolFunc RlsdSig;
    public BoolFunc RingSig;
    }...
    public class SerialPort
    {
    private WithEvents ev;
    private ManualResetEvent recvrEvent;//接收数据线程启动的信号
    private ManualResetEvent writeEvent;
    private Thread rxThread; //接收数据的线程
    public SerialPort(WithEvents ev)
    {
       this.ev = ev;
    }
    //打开串口
    protected bool Open(...) //就是我前面调用的this.Port.Open
    {
       ...
       this.recvrEvent = new ManualResetEvent(false);
       ...
       //启动线程 
       this.rxThread = new Thread(new ThreadStart(ReceiveThread));
       this.rxThread.Priority = ThreadPriority.AboveNormal;
       this.rxThread.Start();
       // Wait for receive thread to start.
       this.recvrEvent.WaitOne(500, false);
       //成功打开了串口
       
    }
    private void ReceiveThread()
    {
        //接收数据
        //触发事件
        ...
        this.OnRxChar(buf);
    }
    }
      

  18.   

    问题还是会出在这里的:
    internal void OnRecvI(byte[] b)
    {   //我在这里处理接收到的字节:b
       //将收到的b显示到界面上    <-------------如何控制主线程的界面?
    }
      

  19.   

    或者你更换一种方式:这段代码更改为:放在一个线程里面。而对于SerialPort类,内部不开线程。即:线程放到调用者那里处理。this.Func = new WithEvents();

    this.Func.Error   = new StrnFunc(this.OnError);
    this.Func.RxChar  = new ByteFunc(this.OnRecvI);//OnRxChar
    this.Func.CtsSig  = new BoolFunc(this.OnCts);
    this.Func.DsrSig  = new BoolFunc(this.OnDsr);
    this.Func.RlsdSig = new BoolFunc(this.OnRlsd);
    this.Func.RingSig = new BoolFunc(this.OnRing);
    this.Port = new SerialPort(this.Func);
             if(this.Port.IsOpen == false)
                  this.Port.Open(this.PortIndex);//打开串口