代码之家  ›  专栏  ›  技术社区  ›  devoured elysium

在多线程环境中锁定什么和不锁定什么(信号量和共享内存)

  •  2
  • devoured elysium  · 技术社区  · 14 年前

    我正在实现一个简单的生产者/消费者程序,它有一些信号量和共享内存。为了简单起见,假设我的程序中只有一块共享内存和一个信号量。

    一开始,我认为我只需要把那些试图写入共享内存块的关键部分代码位考虑在内。但是,由于共享内存块由1024字节组成,我不能同时读取所有数据(这不是一个原子操作),所以确实有可能,当我从中读取数据时,生产者会过来并开始在其中写入数据,因此读取器将获得一半旧数据,一半新数据。由此,我只能认为我还必须将共享内存读取逻辑放在“信号量”块中。

    现在,我有很多这样的代码:

    if (sharedMemory[0] == '0') { ... }
    

    在这种情况下,我只是在内存中寻找一个字符。我想我不必担心在这里设置信号灯,对吧?

    如果我有一些东西

    if (sharedMemory[0] == '0' && sharedMemory[1] == '1') { ... }
    

    从我的角度来看,我想这是两个操作,我必须把它看作一个关键部分,因此必须在它周围放置一个信号量。我说得对吗?

    谢谢!

    2 回复  |  直到 14 年前
        1
  •  1
  •   Donnie    14 年前

    从技术上讲,在多核或多处理器系统中,唯一具有原子性的是汇编操作码,这些操作码被专门记录为原子的。即使是读取一个字节,在您读取它之前,另一个处理器出现并修改它的可能性也很小,除了在某些情况下处理CPU缓存和对齐的内存块(有趣的线程: http://software.intel.com/en-us/forums/showthread.php?t=76744 ,有趣的是: http://www.corensic.com/CorensicBlog/tabid/101/EntryId/8/Memory-Consistency-Models.aspx )

    您必须使用内部保证原子性的类型,或者特别保护多线程多核系统上的访问。

    (在.NET和JVMs这样的IL平台上,答案可能会稍有变化,因为它们对什么是原子的和什么不是原子的做出了自己的保证)。

        2
  •  1
  •   spstanley    14 年前

    当然,锁定非原子操作,检查两个不同的值将被视为非原子操作,但如果处理器不缓存结果,您可以使用一些技巧来检查最多4个字节或更多字节。你必须考虑如何使用你的数据。但基本上,任何对共享内存的访问都应该有一个信号量。