如果在下面的代码中解锁后,Linux上下文可以切换吗?如果有两个线程调用此代码,我们就会遇到问题

inline bool CMyAutoLock::Lock(
    pthread_mutex_t *pLock,
    bool bBlockOk
)
throw ()
{
    Unlock();
    if (pLock == NULL)
        return (false);
// **** can context switch happen here ? ****///
    return ((((bBlockOk)? pthread_mutex_lock(pLock) :
        pthread_mutex_trylock(pLock)) == 0)? (m_pLock = pLock, true) : false);
}

最佳答案

Inline使函数像宏一样工作。内联与原子无关。

AFAIK内联是一个提示,gcc可能会忽略它。内联时,将内联函数中的代码B复制到调用方函数A中。从A到B不会有任何调用。这可能会使您的exe速度更快,但代价是变得更大。大概?如果您的内联函数很小,则exe可能会变小。如果内联使优化func A更加困难,则exe可能会变慢。如果您未指定内联,则在很多情况下gcc都会为您做出内联决策。类的成员函数是默认的内联函数。您需要明确告诉gcc不要自动内联。另外,关闭优化后,gcc不会内联。

链接器不会内联。因此,如果模块A extern引用了标记为内联的函数,但是代码在模块B中,则模块A将对该函数进行调用,而不是对其进行内联。您必须在头文件中定义函数,并且必须将其声明为extern inline func foo(a,b,c)。 Its actually a lot more complicated.

inline void test(void); // __attribute__((always_inline));

inline void test(void)
{
    int x = 10;
    long y = 10;
    long long z = 10;
    y++;
    z = z + 10;
}
int main(int argc, char** argv)
{
    test();
    return (0);
}

不内联:
!{
main+0: lea    0x4(%esp),%ecx
main+4: and    $0xfffffff0,%esp
main+7: pushl  -0x4(%ecx)
main+10: push   %ebp
main+11: mov    %esp,%ebp
main+13: push   %ecx
main+14: sub    $0x4,%esp
!   test();
main+17: call   0x8048354 <test>    <--- making a call to test.
!   return (0);
main()
main+22: mov    $0x0,%eax
!}
main+27: add    $0x4,%esp
main+30: pop    %ecx
main+31: pop    %ebp
main+32: lea    -0x4(%ecx),%esp
main+35: ret

排队:
inline void test(void)__attribute__((always_inline));


!   int x = 10;
main+17: movl   $0xa,-0x18(%ebp)                  <-- hey this is test code....in main()!
!   long y = 10;
main+24: movl   $0xa,-0x14(%ebp)
!   long long z = 10;
main+31: movl   $0xa,-0x10(%ebp)
main+38: movl   $0x0,-0xc(%ebp)
!   y++;
main+45: addl   $0x1,-0x14(%ebp)
!   z = z + 10;
main+49: addl   $0xa,-0x10(%ebp)
main+53: adcl   $0x0,-0xc(%ebp)
!}
!int main(int argc, char** argv)
!{
main+0: lea    0x4(%esp),%ecx
main+4: and    $0xfffffff0,%esp
main+7: pushl  -0x4(%ecx)
main+10: push   %ebp
main+11: mov    %esp,%ebp
main+13: push   %ecx
main+14: sub    $0x14,%esp
!   test();                           <-- no jump here
!   return (0);
main()
main+57: mov    $0x0,%eax
!}
main+62: add    $0x14,%esp
main+65: pop    %ecx
main+66: pop    %ebp
main+67: lea    -0x4(%ecx),%esp
main+70: ret

您可以确定的唯一功能是gcc atomic builtins。一个简单的操作码汇编指令可能也是原子的,但实际上并非如此。到目前为止,以我的经验,在6x86上设置或读取32位整数是原子的。您可以通过查看生成的汇编代码来猜测一行c代码是否可能是原子的。

上面的代码以32位模式编译。您会看到long long需要2个操作码才能加载。我猜那不是原子的。整数和长整数需要设置一个操作码。可能是原子的。 y++是用addl实现的,这可能是原子的。我一直在说这可能是因为CPU上的微代码可以使用多个指令来实现操作,而对此的知识高于我的薪水等级。我假设所有32位写入和读取都是原子的。我认为增量不是,因为增量通常是通过读取和写入来执行的。

但是请检查一下,以64位编译时
!   int x = 10;
main+11: movl   $0xa,-0x14(%rbp)
!   long y = 10;
main+18: movq   $0xa,-0x10(%rbp)
!   long long z = 10;
main+26: movq   $0xa,-0x8(%rbp)
!   y++;
main+34: addq   $0x1,-0x10(%rbp)
!   z = z + 10;
main+39: addq   $0xa,-0x8(%rbp)
!}
!int main(int argc, char** argv)
!{
main+0: push   %rbp
main+1: mov    %rsp,%rbp
main+4: mov    %edi,-0x24(%rbp)
main+7: mov    %rsi,-0x30(%rbp)
!   test();
!   return (0);
main()
main+44: mov    $0x0,%eax
!}
main+49: leaveq
main+50: retq

我猜想addq可能是原子的。

10-08 08:16
查看更多