使用Linux的克隆(2)线程时可以使用哪些C ++同步原语? 我特别是不能使用pthreads,因为我正在构build一个共享库,用不同的定义来replace许多pthreads的函数调用,但是我需要某种types的互斥体。
编辑:我可能会说话太快,我看着pthread文档,他们使用futex(2)来实现这些原语。 我假设我也是这么做的?
你可以使用futex
http://en.wikipedia.org/wiki/Futex
这里是简单的互斥和基于futex的cond var http://locklessinc.com/articles/mutex_cv_futex/
根据您的同步工具的要求,您也可以使用原子操作。 例如, __sync_lock_test_and_set
的__sync_lock_test_and_set
可以很容易地用于自旋锁。 这种避免系统调用的用户空间锁在许多情况下比基于内核的解决方案更有效。
编辑:这是如果你只有几个指示来保护的情况下。 那么,拿住锁的一个已经占用自旋锁的线程被中断的可能性非常小。 如果发生这种情况,那么等待时间将会是一些调度周期,在现代系统中应该只是实时系统的一个不行。 平均等待时间应该可以忽略不计。
在Ulrich Drepper的论文“互斥体是棘手的”中描述了基于futex的互斥体的正确实现。 osgx在他的评论中给出的链接已经过时了。 当前版本在这里:
http://people.redhat.com/drepper/futex.pdf
它不仅包括代码,还包括为什么它是正确的非常详细的解释。 来自纸张的代码:
class mutex { public: mutex () : val (0) { } void lock () { int c; if ((c = cmpxchg (val, 0, 1)) != 0) do { if (c == 2 || cmpxchg (val, 1, 2) != 0) futex_wait (&val, 2); } while ((c = cmpxchg (val, 0, 2)) != 0); } void unlock () { if (atomic_dec (val) != 1) { val = 0; futex_wake (&val, 1); } } private: int val; };
cmpxchg()和atomic_dec()分别可以通过__sync_val_compare_and_swap()和__sync_fetch_and_add()来实现,它们不是标准的C,而是由CLANG支持的GCC和AFAIK。
请注意,futex()是Linux特有的。 FreeBSD有一个仿真AFAIK,但我不知道你是否可以本地访问它。 如果您想要定位除Linux之外的其他平台,则不能使用futex()。 但是由于您使用的是特定于Linux的clone(),所以您可能不在乎。
关于你写一个pthreads-replacement的概念:
算了吧。
我自己走了这条路线,因为我想要克隆()提供一些行为,但不是由pthread_create()。 过了一会儿,我放弃了。 glibc是建立在你正在使用pthread的假设之上的。 即使(尤其是)如果你不链接到-lpthread,glibc也包含pthread特定的行为。 让我放弃克隆()的事情是errno。 在多线程应用程序中,除非要使用全局互斥锁来同步每个libc调用,否则必须提供线程本地errno。 你通过实现__errno_location()来做到这一点。 不幸的是,glibc在某些地方有自己的__errno_location硬编码,不会使用替换。
换句话说:如果你想使用你自己的线程库,你不能使用glibc,至少不是没有阅读你使用的每个函数的源代码,并准备在必要时替换它。 而如果你想用uClibc来代替,我将不得不让你失望。 他们从glibc复制了部分实现,至少老版本有上面的__errno_location问题。
我的解决办法是放弃战斗的线程。 我现在使用pthread_create()来创建我的线程(当然有一个很好的C ++包装)。 虽然我还没有尝试过,但是unshare(2)系统调用应该允许我改变那些我希望通过clone()设置的线程方面,pthread_create()不支持。 如果这不起作用,我将采用glibc的源代码pthread_create(),并将我的选项加入到clone()的调用中,其余部分保持一致,这样我就不会破坏兼容性。
至于同步原语:使用pthread_create()不会强制您使用pthread_mutex和company。 因为我正在写一个虚拟机,每个对象都有一个互斥锁,所以我不需要pthread_mutex_t的空间开销。 相反,我从上面的文件中使用了Drepper的Mutex类。 你可以自由地混合和匹配pthread的原语和你自己的。 只要有可能,你应该使用pthread版本,因为它们经过了很好的测试。 但是对于特殊情况(如极其轻量级的互斥体),可以创建自己的基于futex的基元。