小弟做一个软件,c#多线程的,一个主线程,处理用户的点击操作,一个辅助线程处理串口送来的数据,用户点击一个按钮,后我发送一些数据出去,下位机返回一些对应的数据,如果收到数据就把一个全局变量 byte 赋值为0x01;我在按钮的功能函数中睡眠一小会,确保数据已经发送完成,但是,遇到了奇怪的问题,明明数据发送来了,赋值操作已经在辅助线程中进行了,但是主线程中的依然是老数据(初始赋值0x03),不论你sleep多久。后来吧 前面加了修饰符 static,还有volatile,等,均无效;但是偶尔一次,我在主线程中加入了以messbox.show函数,发现数据成功更新,正常了,我晕倒了,这是什么情况,大侠给解释下,总不能总是给弹出对话框吧
send_data(send_buffer, 9);
                Thread.Sleep(500);
                while(_02==0x03 && count++ < 3)
                {
                    Thread.Sleep(100);                   
                }
                MessageBox.Show("asd");//不加这两行就是老数据,加了就是新数据
                MessageBox.Show("asd");
                if (_02 == 0x01)
                {
                    MessageBox.Show("ok");
                    break;
                }

解决方案 »

  1.   

    可能是数据太快了....就这和其他人经常问的一个问题:设断点就没事,不设断点就有问题。
    因为设断点和MessageBox一样,让程序等一段时间才执行下面的代码
      

  2.   

    你何必用Thread.Sleep(100)呢,用委托不是很好,你这样,万一数据就是没过来怎么办,委托吧,多年的多线程经验,不应该用怎么笨的方法来判断数据是否回执吧~~~
      

  3.   

    如果真的和messagebox有关的话也许doevent一下就行?
      

  4.   

    有个包是要接收22个byte才开始的,但是不该出现上面的情况啊,
      

  5.   

    你的count在什么地方重置为0?
      

  6.   

    这种错误,很明显就是你的Sleep没生效或是休眠的时间不够长,代码再看看吧。
      

  7.   

    未曾休眠过10s发现依然如故,不过只要弹出个messbox马上就正常,我很纳闷
      

  8.   

    _02在哪定义的?
    将thread.sleep(TIME)延长点时间试试
      

  9.   

    多线程操作加锁吧。。
    用lock
      

  10.   

    接受开个线程,有数据然后委托事件通知界面主线程处理,sleep什么啊,你知道消息什么时候能回来?
      

  11.   

    用信号量吧线程通知。
    不要用静态变量或者 vloite。不可靠。
      

  12.   

    哦,对还有Invoke,这个用起来比较简单,实用。
      

  13.   

    这个问题很好分析,从你描述的现象看,你的主线程被占用的情况下数据无法更新,所以你应该找找更新数据的地方和主线程是什么关系,一定是使用了Invoke调用主线程更新。另外MessageBox里面会做DoEvent(),这时主线程的消息泵会处理,所以你才会有机会更新数据。
    如果你不会找问题的话我给你出一个小招,你在更新数据的地方下个断点,断到之后看看堆栈,99.9%是在主线程中更新的。这个问题主要就是由于你不懂多线程造成的。另外,从你的帖子里可以看出,你对多线程可以说是一窍不通,建议你有时间可以补习补习。
      

  14.   

    用AutoResetEvent WaitOne等待操作返回
    而不是用一个信号变量和Sleep被动等待
      

  15.   

    请在同一个线程中调用SerialPort的内部方法,即使需要多线程,涉及到读写的部分都委托到同一个线程,也就是创建SerialPort对象的那个线程中去执行,否则就可能出现各种不正常现象。
      

  16.   

    you get it!!  可惜了还是在我找到问题后才看到你的帖子,处理数据的线程我调用了主线程的一个控件,当时因为偷懒,设置为不检查跨线程调用问题,主线程睡眠,辅助线程被挂起,不小心害死猫
      

  17.   

    you get it!!  可惜了还是在我找到问题后才看到你的帖子,处理数据的线程我调用了主线程的一个控件,当时因为偷懒,设置为不检查跨线程调用问题,主线程睡眠,辅助线程被挂起,不小心害死猫
      

  18.   

    你说对了,我是学机械的,半路出家,实际上这个是副业,呵呵,是套RFID系统的写卡器,刚写完下位机,来写上位机的时候出现了问题,谢谢
      

  19.   

    把messagebox改为application.doevent即可。
      

  20.   

    不仅仅是invoke,这个不行,必须begininvoke;我觉得你知道区别
      

  21.   


    小伙子,讨论问题要注意态度,态度不好,别人还愿意和你分享知识吗。虽然个别人言语不妥,但说得并非没有道理。虽然你用C#多年,但看你线程写成这样,俺也忍不住说一句:你的多线程技能需要提高。回到你的代码来看,业务俺不熟悉不多说,但只看sleep的调用,基本上可以判定你的线程实现是有问题的。也许今天运行没问题,哪天要求换个用法就会出错。俺审核别人的代码时,发现线程里有sleep的,一律要求改掉。即便是工作线程,也不可以随意使用sleep,这是写多线程的大忌。现在不懂没关系,也许哪天你就明白俺为什么这么说了。
      

  22.   


    sleep这东西,有时候还真不得不用
      

  23.   


    真的吗?WaitForXXXObject不可以代替sleep?你的代码要是给俺审核,凡是有sleep的,100%会被俺打回重写。
      

  24.   


    确实还没这么用过,能否给个简单的例子呢?
    比如,通过C#进行Excel创建编辑操作后再打开这个Excel文件,在Excel保存和打开中使用sleep,确实我觉得用sleep实在是无赖的方式,如有实例麻烦发送邮件[email protected]
      

  25.   


    抱歉,没有C#代码可以给你参考,俺是搞C++的,C#不懂,不过道理相同。你说的exel打开编辑和保存,可以放在工作线程里去做,然后在主线程(也就是你的主窗口关联的线程)处理工作线程发送的自定义消息。假如工作线程叫A,在做完exel相关的任务之后,post一个消息给主窗口,主窗口收到这个消息后,弹出个对话框告诉用户exel处理完了。这样,主窗口就不会因为调用了sleep卡在那几秒钟,给用户的感觉好一些。不一定非要使用WaitForSinggleObject之类的函数,方法很多种,选适合项目要求的即可。
      

  26.   

    主要是类似Excel的外部程序是独立进程,在所谓的主线程中是没办法判断类似Excel文件是否创建完成或者已经关闭了,现在很多的文件或者程序是只允许已独占方式来操作的,否则会出现类似"文件正在被其他进程使用"之类的错误。所以我本质是想问下windows内部是否有这样的方法来监控系统的进程执行情况的。
      

  27.   


    你的主要问题,应该是想知道什么时候操作完exel,而不是监视exel进程执行情况,对吧?office的2次开发俺接触过一些,关于word的,非exel。俺记得保存word,是有方法可以调用,是个阻塞函数。调用完了,保存也就完了,没那么复杂。exel应该也是如此,你查一下office2次开发相关资料吧。你的工作线程,如果是通过COM来操作exel,是可以知道什么时候操作完的。如果使用了一些非常规的办法操作exel,恐怕就没办法知道exel操作情况了。
      

  28.   


    你不会是写个独立的工作线程只做心跳检测功能吧?然后每sleep几秒就发送心跳包给服务器?奢侈啊。
      

  29.   

    一般多线程处理,先看看API有没有支持异步处理;(这个会比较稳定,快速,毕竟是硬件驱动的)
    能不用Thread尽量不用;
    异步处理后,加个callback就perfect了;
      

  30.   

    本身:“取消检查非法跨线程”功能,就是错误的开始;
    这只是C#.net很早之前的版本,来后,都不使用该功能了;除非,根本不在乎准确性、稳定性;
    能用异步函数则用;当年俺,使用COM口与下位机通讯,畅通无阻;
      

  31.   

    你说的有一定的道理,但是在实际的应用的中,Socket的客户端基本都是不用线程去发送数据的,而且客户端程序的发送数据也是不定时的,比如交互时响应式的
      

  32.   


    不对啊,你刚才问的不是心跳包么。心跳包,无论是TCP还是UDP,都要定时发送的。交互响应是和业务相关,和心跳包不一样,自然不需要定时发送。
      

  33.   


    呵呵,哥们,我也只是探讨学习啊,我的目的是你刚开始说的必须不能用Sleep,我就是想探讨某些方面的代码怎么写。
      

  34.   


    呵呵,不用Sleep的话,可以有很多替代的方式。Sleep在网络编程时最大的问题是会导致丢包,这个是不可接受的。如果是普通界面编程,可能会造成UI没响应或者响应缓慢,写得差的话,甚至会有死锁。所以俺审核代码时,有sleep的一律打回重写。
      

  35.   

    网络编程写过,自己出书的时候,配套了个绿色的web服务器,运行良好,未出现过超时或者丢失文件的情况,何况数据传输过程全程加密,web请求是多线程并发的,我也用了sleep;关键是怎么用法,没必要非要不让用啊,不然微软干脆去掉sleep算了,ui不响应了,说明主线程卡死,这个是写程序的基本功了,这个处理不好当然卡死,所以,都没有必要一棒子打死。纯属技术讨论,大家勿动肝火,呵呵,小弟学机械的,各位多多指教,我乃外行
      

  36.   

    呵呵,在接收是一定不要用Sleep的,但是在发送心跳等自动维护的方面还是可以有的,但是Sleep的代码看怎么写,如果直接Sleep 5秒,10秒的肯定有问题,会在退出程序、清理等待方面出现问题
      

  37.   


    呵呵,出书了都,但愿你的书能帮到别人。实际的项目中,一般是不建议使用sleep的。原因是,一方面有潜在的死锁可能,另一方面会有响应时滞。尤其是项目大、模块多、业务流程繁琐的时候,一个小问题带来的影响会成倍放大,因此查找这个小个问题需要开发人员相互沟通,这都是开销。当然,不用sleep也会存在死锁的的可能,但比用sleep小得多。看你首帖代码,真不敢确定你对多线程很熟悉,不好意思,再次冒犯了。
      

  38.   

    大牛客气了,不是计算方面的书,我是做机械电子的,很久不来csdn了,回来发现气氛还是很活跃的,那几个代码是随手写来,目的是测试stm32的单片机对rfid的操作性能,测试不通过,改来改去,没法看,让大家见笑了,呵呵。71楼所说的,我也看到过sp1234几次这个问题,他实在该修炼说话的方式;不过他说的对,我是半路出家
      

  39.   


    sp1234是装 B大神 ,早就有人给盖棺定论了,这可不是我说的
      

  40.   

    能给给串口多线程的例子吗?邮箱:[email protected].谢谢
      

  41.   

    第一次看到依靠Thread.Sleep来等待数据发送的.从socket读取数据是一个阻塞方法, 每次把读取到的数据缓存起来就行.Thread.Sleep挂起线程后, 有可能造成其它线程也无法修改数据.或者说 线程唤醒后, 读取的不是本来的数据.Messagebox.Show也会暂停当前线程的执行, 但是人家微软不是用sleep阻塞当前线程的, 人家用的是合理的方法, 所以你Messagebox.Show之后, 收到了数据.总之, 别依靠瞎蒙来编程, 现在很多人真是无知者无畏.
      

  42.   

    用BackGroundWork吧,比直接用线程好多了
      

  43.   

    虽然c#线程使用了很多年,但知识看来很狭窄。这个while循环完之后判断==0x01之前也的加上sleep,不过这不是个好实践,最好的方法还是用事件量来等待。
      

  44.   

    同感啊,非常厌恶看到别人胡乱使用sleep。
    说实在90%的sleep都是被乱用的,这些人都不了解自己在做什么,甚至为了停顿一下等原因在主线程中使用sleep,奇葩太多了。
    相对于见到sleep语句,我更愿看到goto语句,编程书上说尽量不要使用goto语句,在我看来sleep倒是尽量不要使用的语句,原因就不解释了。
    事实上能使用goto语句的人基本上水平要比这些随便使用sleep的人高很多。
      

  45.   

    靠sleep多不靠谱啊,发消息时候就disable掉按钮,收到数据时将按钮enable,还sleep个啥。多线程时在线程中操作控件需要判断是否跨线程调用这是基本操作规范
      

  46.   


    我怎么没看清楚了,第一个,你说"我在按钮的功能函数中睡眠一小会,确保数据已经发送完成". 然后辅助线程中收到数据后对赋值,然后主线程中去判断的值嘛“,
    我的意思也很简单,用户按下按钮,就将按钮disable,辅助线程收到数据后使用代理将按钮enable,根本不需要sleep操作,更何况你在主线程里面sleep,主界面调sleep时间稍长就会让用户感觉假死了。
    第二个,你说了原因是“处理数据的线程我调用了主线程的一个控件,当时因为偷懒,设置为不检查跨线程调用问题,主线程睡眠,辅助线程被挂起,不小心害死猫”,于是我说“多线程时在线程中操作控件需要判断是否跨线程调用这是基本操作规范”,哪里没说到点子上了???
      

  47.   

    是这样的,按下按键已经disable了按钮,你知道iso1443a的卡有个情况,就是连续读写会失败,这个是卡标准里面规定好的,数值很关键,仅仅操作一次那么有50%以上的几率读写卡失败(卡本身特性),严重影响用户体验,并且写入成功或者失败需要弹框提示用户,所以我需要分析返回数据(10多个byte)来判断是否再次尝试写入操作,如果是加减值操作,则决不允许重复进行,所以仅仅disable  enable 是不够的,最多0.3s的睡眠,期间就是不响应用户输入,时间很短,基本感觉不到。。大家讨论而已,
      

  48.   


    不敢苟同,找你这么说我们公司所有的自动化机器代码去不能合格
    不设置线程sleep的话 就一直等待硬件响应的话 那是本末倒置 
      

  49.   


    合格不合格,看公司怎么规定了,在俺这是不合格的。
    线程等待事件发生,最好不使用sleep的最大原因不是不能实现功能,而是线程一旦sleep了,随机发生的事件无法及时被线程捕获。这样给客户的感觉是,你们的东西(硬件和软件)响应太慢了。另外,俺没搞明白你说的本末倒置啥意思。
      

  50.   

    1)发消息让他来取
    2)全局变量,发消息让他来取
    3)volatile