代码之家  ›  专栏  ›  技术社区  ›  johnnycrash

Linux线程同步

  •  5
  • johnnycrash  · 技术社区  · 15 年前

    我是Linux和Linux线程的新手。我花了一些时间在google上试图理解线程同步可用的所有函数之间的差异。我还有一些问题。

    我发现了所有这些不同类型的同步,每种同步都有许多功能,用于锁定、解锁、测试锁等。

    • gcc原子操作
    • 期货交易所
    • 互斥器
    • 自旋锁
    • 赛克斯洛克
    • 小鸡
    • 条件
    • 信号量

    我目前(但可能有缺陷)的理解是:

    信号量是全进程的,涉及文件系统(实际上我认为是),而且可能是最慢的。

    futex可能是互斥锁、自旋锁、seklocks和rculocks使用的基本锁定机制。futex可能比基于它们的锁定机制更快。

    自旋锁不会阻塞,因此可以避免上下文切换。然而,它们避免了上下文切换,代价是在释放锁(旋转)之前消耗cpu上的所有周期。它们应该只在多处理器系统上使用,原因很明显。千万不要睡在旋转锁里。

    seq锁只是告诉你当你完成工作时,如果一个作者更改了工作所基于的数据。在这种情况下,你必须回去重复这项工作。

    原子操作是最快的同步调用,可能用于所有上述锁定机制。您不想对共享数据中的所有字段使用原子操作。当您访问多个数据字段时,需要在锁标志上使用锁(mutex、futex、spin、seq、rcu)或单个原子操作。

    我的问题是这样的:

    1. 到目前为止我的假设是对的吗?

    2. 有人知道各种选项的CPU周期成本吗? 我正在向应用程序中添加并行性,这样我们就可以获得更好的墙时响应,而代价是每个框运行更少的应用程序实例。表演是最重要的。我不想在上下文切换、旋转或读写共享内存时占用cpu。我非常关心消耗的CPU周期数。

    3. 哪种锁(如果有的话)可以防止调度程序中断线程或中断…或者我只是个白痴,所有的同步机制都会这么做。什么样的中断被阻止?我可以只在锁定线程的CPU上阻塞所有线程或线程吗? 这个问题源于我害怕中断一个为一个非常常用的函数持有锁的线程。我希望调度程序可以调度任何数量的其他工作进程,这些工作进程可能会运行到此函数,然后由于它被锁定而阻塞。很多上下文切换将被浪费,直到带有锁的线程重新调度并完成。我可以重新编写这个函数以最小化锁时间,但它仍然是如此的普遍,我想使用一个锁,防止中断…在所有处理器。

    4. 我在写用户代码…所以我得到的是软件中断,而不是硬件中断…对吧?我应该远离任何函数(自旋/顺序锁),其中有“irq”一词。

    5. 哪些锁用于编写内核或驱动程序代码,哪些锁用于用户模式?

    6. 有人认为使用原子操作让多个线程在链表中移动是疯狂的吗? 我正在考虑原子式地将当前项指针更改为列表中的下一项。如果尝试成功,则线程可以安全地使用当前项在移动之前指向的数据。其他线程现在将沿着列表移动。

    7. 未来?有什么理由用它们代替互斥锁吗?

    8. 有没有比在没有工作的情况下利用一个条件来睡眠线程更好的方法呢?

    9. 当使用gcc原子操作,特别是test_和_集时,我是否可以通过先执行非原子测试,然后使用test_和_集进行确认来提高性能? 我知道这是个案,所以这是个案。有大量的工作项目,比如说数千件。每个工作项都有一个初始化为0的标志。当线程对工作项具有独占访问权时,标志将为1。将会有很多工作线程。任何时候线程正在寻找工作,它们都可以非原子地测试1。如果他们读到1,我们肯定这项工作是不可用的。如果他们读到一个零,他们需要执行原子测试来确认。因此,如果原子测试集是500个CPU周期,因为它正在禁用管道,会导致CPU通信和二级缓存刷新/填充….一个简单的测试是一个周期…然后,只要我有一个更好的比率500比1,当它来绊倒已经完成的工作项目…这将是一个胜利。

    我希望使用互斥锁或自旋锁来保护我一次只希望系统上一个线程(而不是jsut-cpu)访问的代码段。我希望节省使用gcc原子操作来选择工作,并尽量减少互斥锁和自旋锁的使用。例如:可以检查工作项中的标志,以查看线程是否已处理过它(0=否,1=是或正在处理)。一个简单的test_and_集合告诉线程它是否有工作或需要继续。我希望在有工作的时候用条件唤醒线程。

    谢谢!

    5 回复  |  直到 14 年前
        1
  •  2
  •   nategoose    15 年前

    应用程序代码可能应该使用posix线程函数。我想你有这么多的手册

    man pthread_mutex_init
    man pthread_rwlock_init
    man pthread_spin_init
    

    仔细阅读它们以及对它们进行操作的函数,以了解您需要什么。

    如果你在做内核模式编程,那就另当别论了。你需要对你在做什么,花多长时间,以及在什么样的环境中被调用有一个感觉,才能知道你需要使用什么。

        2
  •  2
  •   johnnycrash    14 年前

    感谢所有回答的人。我们使用gcc原子操作来同步所有线程。原子操作比设置一个没有同步的值慢大约2倍,但是数量比锁定一个互斥锁、更改值、然后解锁互斥锁快(当你开始让线程进入锁时,速度会变得非常慢…)我们只使用pthread掴create、attr、cancel、an杀戮。我们使用pthread_kill来向线程发送信号,使其在进入睡眠状态时醒来。这种方法比cond_wait快40倍。所以基本上…如果有时间的话,使用pthreads_mutex 浪费 .

        3
  •  0
  •   Sebastian Marcet    15 年前

    此外,你还应该检查下一本书

    • pthreads编程:posix 更好的多处理标准

    • 用posix(r)线程编程
        4
  •  0
  •   Sebastian Marcet    15 年前

    关于问题8 有没有比在没有工作的情况下利用一个条件来睡眠线程更好的方法呢? 是的,我认为最好的方法不是睡觉 正在使用函数sem_post()和sem_wait of“semaphore.h”

    当做

        5
  •  0
  •   Tim Post Samir J M Araujo    15 年前

    关于futex的一个注释-它们被称为 快速用户空间互斥 . 对于futex,只有在需要仲裁时才涉及内核,这就提供了速度和节省。

    实现futex可以是 extremely tricky (pdf),调试它们会导致疯狂。除非你真的,真的,真的需要速度,否则通常最好使用pthread互斥实现。

    同步从来都不是 easy ,但是尝试在用户空间中实现自己的功能会使它变得非常困难。