none
在异步通信时如何临时阻止主线程运行? RRS feed

  • 问题

  • 尝试搞了一个用TcpClient异步接收发送的东西,在发送的时候碰到一些问题,主线程刷数据刷得太快了,就是for循环那里,结果是前面的还没发完,后面的旧接着刷上去了,在非调试下另一边的接收方只能接到前面2-3条,后面的都没有,当在BeginWrite处设立断点一条一条来按时,对面就能全部接收到,据说用ManualResetEvent的WaitOne 可以在发送时先临时阻止主线程 For 循环的执行,之后再用 Reset 使其继续 ,在 SendData 一开始就 WaitOne ,然后在 SendCallBack 最后 Reset ,但运行起来完全没有效果,这个应该怎么弄?



    定义有
    private NetworkStream ns;

    private struct msgstruct 
    {
          public string msg;
         public string st;

    }

    protected ArrayList SendArrList = new ArrayList();  //用来装msgstruct 的

    点击按钮触发
    for (int isend = 0; isend < SendArrList.Count; isend++)
     {
              msgstruct sendstruct = (msgstruct )SendArrList[isend];  //sendstruct 是一个结构,里面是发送的信息msg 和执行的策略st,

              string revder = sendstruct.msg;
              string sdate = sendstruct.st;
              SendData(“sa”, sendstruct.msg, sendstruct.st);
       }

     private void SendData(string rever,string msg,string lvl) //发送
     {
            byte[] reverbit  = reverbit.GetBytes(rever);
            byte[] msgrbit  = msgbit.GetBytes(msg);
            byte[] lvlbit  = lvlbit.GetBytes(lvl);

           MemoryStream mem = new MemoryStream();

               mem.Write(reverbit  , 0, reverbit.Length);
                mem.Write(msgrbit  , 0, msgrbit.Length);
                mem.Write(lvlbit  , 0, lvlbit.Length);

          byte[] msgbody = mem.ToArray();

           ns.BeginWrite(msgbody , 0, msgbody.Length, new AsyncCallback(SendCallBack), ns);   //设置断点位置
                    
            ns.Flush();

    }

    private void SendCallBack(IAsyncResult iar)   
     {
                try
                {
                    ns.EndWrite(iar);
                   
                }
                catch (Exception e)
                {
                   
                }
     }

    2009年7月6日 8:47

答案

  • 正常的办法是把所有要发的东西放在队列里  把队列作为参数  放在同步状态的 sync object中

    在不断的  endsend 线程中 从同步状态中的队列取出下一个内容  再次begingsend   这样就可以高效率的循环了
    紫柔版主的头像真叫萌得一个不行啊。。。。
    答案800 撒花
    2009年7月6日 9:15
    版主

全部回复

  • 我也有遇到过类似的问题。

    我的解决方式是:状态位+Thread.Sleep;

    思路为:

    bool _Complete=false;

    for(...)
    {
    ...
    while(!_Complete){System.Thread.Sleep(400); _Complete=false;}
    }

    private void SendCallBack(IAsyncResult iar)   
     {
                try
                {
                    ns.EndWrite(iar);
                    _Complete=true;
                }
                catch (Exception e)
                {
                    
                }
     }

    这个方式 比较 简单,而且通过 修改 不同的  Sleep时间,可以提高  程序 的响应时间!  Sleep 时间 的确认,

    您可以 使用  10/CPU频率*100 公式来获得 ms 优化值


    虫子(Tech-Worm:270816377)
    2009年7月6日 9:11
  • 正常的办法是把所有要发的东西放在队列里  把队列作为参数  放在同步状态的 sync object中

    在不断的  endsend 线程中 从同步状态中的队列取出下一个内容  再次begingsend   这样就可以高效率的循环了
    紫柔版主的头像真叫萌得一个不行啊。。。。
    答案800 撒花
    2009年7月6日 9:15
    版主
  • 我也有遇到过类似的问题。

    我的解决方式是:状态位+Thread.Sleep;

    思路为:

    bool _Complete=false;

    for(...)
    {
    ...
    while(!_Complete){System.Thread.Sleep(400); _Complete=false;}
    }

    private void SendCallBack(IAsyncResult iar)   
     {
                try
                {
                    ns.EndWrite(iar);
                    _Complete=true;
                }
                catch (Exception e)
                {
                    
                }
     }

    这个方式 比较 简单,而且通过 修改 不同的  Sleep时间,可以提高  程序 的响应时间!  Sleep 时间 的确认,

    您可以 使用  10/CPU频率*100 公式来获得 ms 优化值


    虫子(Tech-Worm:270816377)

        这样做会不会导致界面卡住动不了? System.Thead 停掉的范围是整个程序还是后台?
      
    2009年7月6日 9:17
  • 正常的办法是把所有要发的东西放在队列里  把队列作为参数  放在同步状态的 sync object中

    在不断的  endsend 线程中 从同步状态中的队列取出下一个内容  再次begingsend   这样就可以高效率的循环了
    紫柔版主的头像真叫萌得一个不行啊。。。。
    答案800 撒花

     能不能提供个例子?
    2009年7月6日 9:28
  • 刚才试验了下二楼的方法,发现
    private void SendCallBack(IAsyncResult iar)   
     {
                try
                {
                    ns.EndWrite(iar);
                    _Complete=true;
                }
                catch (Exception e)
                {
                    
                }
     }

    是在异步里设置标志位,如果其中一次设置为true时,for那边就有可能瞬时猛得刷几条近来

    2009年7月6日 9:44
  • 不要阻塞主线程。这样很容易造成死锁。
    你可以把你的工作流程写成一个状态机,在工作线程结束时根据状态来执行下一步操作。


    Please mark the post answered your question as the answer, and mark other helpful posts as helpful. This posting is provided "AS IS" with no warranties, and confers no rights. Visual C++ MVP
    2009年7月6日 17:24
    版主
  • TCP 是基于流的协议, 无论你怎么限制, 两个或者多个数据包都有可能连在一起。

    而接受方也并非没有收到数据,而是因为程序没有留意后面的数据而已

    通常我是在数据包的头部标上长度
    2009年7月7日 1:56
  • 刚才试验了下二楼的方法,发现
    private void SendCallBack(IAsyncResult iar)   
     {
                try
                {
                    ns.EndWrite(iar);
                    _Complete=true;
                }
                catch (Exception e)
                {
                    
                }
     }

    是在异步里设置标志位,如果其中一次设置为true时,for那边就有可能瞬时猛得刷几条近来


    您可以参考我的游戏大厅系列  waynebaby.cnblogs.com
    也可以参考 包包的大厅   jax.cnblogs.com
    紫柔版主的头像真叫萌得一个不行啊。。。。
    答案800 撒花
    2009年7月7日 4:02
    版主
  • 不要阻塞主线程。这样很容易造成死锁。
    你可以把你的工作流程写成一个状态机,在工作线程结束时根据状态来执行下一步操作。




    怎么弄法?请示例一下
    2009年7月7日 9:02
  • 异步时好像是先不管之前发送结果就往外送,之后再处理问题,如果需要得知之前的结果再看是否发送第二条,是不是要搞成同步?
    现在我这里看起来也不需要知道确定的发送结果,先扔出去再说,但是又要知道对方收得怎么样了。
    2009年7月8日 8:12
  • 异步时好像是先不管之前发送结果就往外送,之后再处理问题,如果需要得知之前的结果再看是否发送第二条,是不是要搞成同步?
    现在我这里看起来也不需要知道确定的发送结果,先扔出去再说,但是又要知道对方收得怎么样了。
    endsend的时候是可以得到确认标记位的  你仔细看我的代码就知道了哦

    答案900, 目标五颗星
    2009年7月8日 8:22
    版主
  • 异步时好像是先不管之前发送结果就往外送,之后再处理问题,如果需要得知之前的结果再看是否发送第二条,是不是要搞成同步?
    现在我这里看起来也不需要知道确定的发送结果,先扔出去再说,但是又要知道对方收得怎么样了。
    endsend的时候是可以得到确认标记位的  你仔细看我的代码就知道了哦

    答案900, 目标五颗星

    您那个是VB写的吧?
    是不是这里?
     Dim r As Net.Sockets.SocketError
                Socket.EndSend(o, r)

    看不明白,能否用C#解释下
    2009年7月13日 9:22
  • 在for语句下直接加了句
     System.Threading.Thread.Sleep(5);
    好像就可以正常发送了,但sleep的是主线程,看起来依然是治标不治本
    2009年7月14日 1:42

  • 请看下面伪代码


    主线程
    1 准备发送100个包
    2 准备一个100个包的队列 q
    3 连接.beging send ( 取出发送q的第一个 ,asyncObj (里面包含q))

    4                                            完毕处理线程:
    5                                           asyncObj=endsend (); 得到对列q
    6                                            连接.beging send ( 取出发送q的第一个 ,asyncObj (里面包含q))
     

    其中4-6是一直循环的
    答案900, 目标五颗星
    2009年7月14日 5:56
    版主