其中写buffer的线程实时性要求很高,所以任何时候都不希望阻塞这个线程,读buffer的线程没有这样的限制。想了半天,实在没想到好办法

解决方案 »

  1.   

    读的时候如果有写copy出来一份,读线程从copy的buffer里面取数据,读完后删除临时buffer.
    思路是参考Linux2.6内核的RCU机制.
      

  2.   

    laolaoliu2002:你是说由写线程来copy一份出来?不过我现在的情况是还有限制:可能多次读取以前读过的buffer。
    所以也就是需要完全拷贝整个buffer,而不是读完就删除,这样比较费内存。
      

  3.   

    更新过后buffer里面已经不是原来的数据了.你是怎么读取以前读过的buffer的呢?如果能读出来那就不是更新而是重建了新的buffer.
      

  4.   

    楼主功能设计有些问题. 如laoliu所述.
      

  5.   

    读的时间可能会比较长?可以还是用一个临界区保护,设置一个写请求标志,在读的过程中(可能会有循环)随时判断这个写请求标志,如果发现为true了,读就立即取消,退出临界区。  ------临时想的,没有经过验证
      

  6.   

    这个就不能算buffer了,以前写的都得要保留。。
      

  7.   

    更新过后buffer里面已经不是原来的数据了.你是怎么读取以前读过的buffer的呢?如果能读出来那就不是更新而是重建了新的buffer.
    ------------------------------------------------
    这个是一个比较大的buffer,比如64M(buffer的范围是256K到128M,用户可配置),写数据是顺序写入,可能写满了,可以再从头覆盖写入而读数据可能读取buffer里任何一部分有效的数据
      

  8.   

    读的时间可能会比较长?可以还是用一个临界区保护,设置一个写请求标志,在读的过程中(可能会有循环)随时判断这个写请求标志,如果发现为true了,读就立即取消,退出临界区。 ------临时想的,没有经过验证
    -----------------------------------------------------
    读的时间不是很长
    不过你的方法应该不能避免临界区冲突,毕竟线程随时都可能被切换
      

  9.   

    具体点的需求就是这样的:
    线程A从网络上抓包并写入buffer,线程B是UI线程,用户需要随时看到网络数据包的内容,所以需要从buffer读取数据。因为抓包线程实时性很强,所以不能阻塞(事实证明阻塞并且流量很大时肯定丢包)
      

  10.   

    开两个buffer,一个写,一个读,当读完以后就切换两个buffer。这样只需要在切换过程做同步,几乎没有阻塞。
      

  11.   

    To 楼上,如果用两个buffer,好像不用这么麻烦:其中一个buffer(B1)只由写线程操作,另一个buffer(B2)由两个线程同时操作。
    如果写线程发现读线程正在读B2,则不对其进行操作(这里没有阻塞写线程)
    如果读线程发现写线程正在写B2,则阻塞该线程现在是不想用两个buffer,如果用户配置的内存太大,则很浪费memory
      

  12.   

    可以考虑开辟一个虚拟内存共享池, 这样不浪费 physic memory
      

  13.   

    用InterlockExchangePtr原子化写线程的操作
      

  14.   

    设置读写位置标记, 如下:char buf[1024];
    int  nReadPos  = 0;
    int  nWritePos = 0;写的时候从buf+nWritePos 处写入,写完成后要更新nWritePos的位置,
    读的时候从buf+nReadPos  处读取,读完成后要更新nReadPos的位置,保证nReadPos小于nWritePos就行了。
    参考自ACE的ACE_Message_Block
      

  15.   

    给buffer创建一份拷贝,读线程只能读副本当中的内容!
    写线程写完以后重新覆盖拷贝!
      

  16.   

    把对Buffer的读写放在临界区里吧。临界区是线程同步中耗资源比较少的一种同步方式,用这种方式同步时,操作系统不用进行内核/用户切换。
    如果每次都创建copy的话,如果你的buffer比较大,恐怕效率还不及临界区高。
      

  17.   

    用InterlockExchangePtr原子化写线程的操作
    ----------------------------------------------
    这些原子操作好像只能操作一个变量,或者一个指针,读写操作都不可能对一个变量读写就完成的。
    不知道是不是我理解有误
      

  18.   

    或许Exceptional C++里讨论的swap函数对你会有帮助
      

  19.   

    谢谢各位。
    最终的解决方案是采用比较浪费memory的方法,将整个memory分为N个固定长度(长度为网络的MTU,并且在每个块的末尾添加一个指针,如果收到超过MTU的Packet则动态分配一块buffer来存放超过MTU的部分放)的块。另外,还在每个块的尾部设置一个flag,在写之前设置为1,写完成之后设置为2。读线程读取之前判断是否为1,如果是则表示正在写这个块,不再读取这个块。否则设置该flag为3,读取完成之后,再次判断该标志,如果还是3,则表示读取成功,否则表示读取过程中被写线程覆盖过,读取失败。注:对每个块flag的操作均采用 InterLock 的原子操作。这个方案唯一的缺点是比较浪费内存,如果收到的都是较小的Packet的话内存浪费率很高。