如果在下面的代码中解锁后,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可能是原子的。