全部博文(73)
分类: LINUX
2009-04-23 16:24:05
pthread之memory
barries
memory barrier(内存屏障)是为解决内存可视性以及内存排序相关问题提出,是pthread使的一套内存机制,操作系统也可能使用这种机制,但 pthread与OS在这点上是没有交集,互相独立的。此外memory barrier其实就是保证几个代码块之间的同步执行。在pthread中mutex_lock, mutex_unlock可以看作是就是pthread内存屏障机制的外在表现。
首先来看看传说中的内存可视化规则是什么:
我个人觉得,上面的四条是多线程编程的精华中的精华,难懂中最难懂的部分。
为了理解相关的内容,我们说一下内存排序相关的概念:
第7条的内容解决了前6条带来的内存同步的问题与困难,同时也是多线程内存同步问题解决的基础。
以上这些内容都说明:
为编写可移植性代码,总要使用pthread内存可视化规则来保证正确性,而不能依赖于特定硬件和编译器相关的假设。这说明,内存屏障的正确要基于一种规则来进行,就可以保证。
例子包含三个文件:main.h,main.c thread.c,分别用于数据结构,执行体,子线程体的定义。
先看看main.h,注意main.h中的数据结构的声名,没有在int a;前面加volatile关键字,但是多了mutex的定义。用来说明,mutex是内存屏障的内在表现。
#ifndef MAIN_H
#define MAIN_H
#include
#include
#include
#include
#include
#include
#include
typedef struct test
{
int a;
int b;
pthread_mutex_t mutex;
}Test;
#endif
对内存屏障的理解最好与<Pthread之gcc优化>一文一起比较,会能较好的理解。
#include "main.h"
/*请结合thread_vol来研究memory
barrier的效果*/
extern void * change( void * arg );
Test x = { 1, 0, PTHREAD_MUTEX_INITIALIZER };
int main()
{
pthread_t pid;
if ( pthread_create( &pid, 0,
change, 0 ) )
{
printf( "Create thread
error\n" );
exit( -1 );
}
//注意可视性规则1
pthread_mutex_lock( &x.mutex
);
int c = x.a;
pthread_mutex_unlock( &x.mutex
);
while( c )
{
//可视性规则2
pthread_mutex_lock(
&x.mutex );
c = x.a; //正确得到a值,才能退出循环
pthread_mutex_unlock(
&x.mutex );
}
printf( "%d\n", x.b
); //理论上该值不一定正确的打印,事实上我测试了半天,都正常打印了..
//可视性规则3
pthread_join( pid, 0 );
printf( "%d\n", x.b
); //该值正确的打印
return 0;
}
再看看thread.c,它主要将x.a设置为0,以被主线程结束循环,x.a设置为0有内存屏障的保证,从而能正确的被主线程得到。
x.b只有在join之后才可以确定得到,因为x.b并不在mutex的保护之下。
#include "main.h"
extern Test x;
void * change( void * arg )
{
pthread_mutex_lock( &x.mutex
);
x.a = 0;
pthread_mutex_unlock( &x.mutex
);
x.b = 11;
printf( "XXXX\n" );
return (void *)0;
}
该文只是为介绍多线程中比较难懂的内容,对于上面的大量使用加锁、解锁方法并不一定处处适用。当然上面的方法