Wednesday, 4 September 2013

seqlock implement by c++ , like to know if something missed

seqlock implement by c++ , like to know if something missed

I have refered to this webpage , and like to implement a simple seqlock
sample according to it !!
http://www.1024cores.net/home/lock-free-algorithms/reader-writer-problem/improved-lock-free-seqlock
The following is what I compiled at g++ 4.4.6 , running in Linux x86-64
server !!
struct data_t
{
int seq; // sequence number
int data ; // user data
};
struct data_t s1 ;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_spinlock_t spinlock ;
int TheRead()
{
int iret ;
for (;;)
{
int seq1 = s1.seq;
if (seq1 % 2)
continue;
iret = s1.data ;
int seq2 = s1.seq;
if (seq1 == seq2)
return iret ;
else
printf("(%d) != (%d) read again\n",seq1,seq2) ;
} //for
}
void TheWrite(int idx)
{
pthread_spin_lock(&spinlock);
s1.seq += 1; // start writing new object
s1.data = idx ;
s1.seq += 1; // end writing new object
pthread_spin_unlock(&spinlock);
}
void *threadWrite(void *param)
{
int idx ;
for(idx=0;idx<10000;idx++)
{
TheWrite(idx) ;
}
}
void *threadRead(void *param)
{
int idx ;
while(1)
{
idx = TheRead() ;
if(idx==(10000-1))
break ;
printf("(%d)\n",TheRead()) ;
}
}
int main()
{
pthread_t tid[2] ;
pthread_spin_init(&spinlock, 0);
pthread_create(&tid[1] , NULL, threadWrite, (void*)(long)1);
pthread_create(&tid[0] , NULL, threadRead, (void*)(long)0);
pthread_join(tid[0], NULL );
pthread_join(tid[1], NULL );
}
Compiled by g++ testseqlock2.cpp -lpthread -o testseqlock2.exe and run
showes like :
(8756)
(8826)
(17788) != (17790) read again
(9628)
(9747)
look like perfect , since TheWrite is protected by spinlock , I pay my
attention at TheRead, as I know , Intel x86-64 cpu is strong memory model
, so that store/store and load/load barrier work fine !!
Suppose Thread A execute TheRead , at that monent s1.seqno =
10,s1.data=100, at the very monent while Thread A going to execute "iret =
s1.data",Thread B execute TheWrite, Thread B modify seq=11 first , and
modify data=200 and modify seq=12 at last, since the source run in Intel
cpu as I mentioned, so if Thread A execute iret = s1.data and get iret =
200 , then int seq2 = s1.seq; seq2 must be 11 or 12 ,but never 10 !!
It is Because if data=200 means s1.seq = 11 is executed already, in a cpu
with store/store and load/load barrier ,that is why I said : if Thread A
get data = 200 , then seq2 must be 11 or 12 , but never 10 !!!!
I like to know if anything I missed in this simple sample ? currently my
g++ is 4.4.6, so I don't use c++11 acquire/release statement at all , any
comments/suggestions are welcome !!!!
One more thing , the source I refered to from webapge I mentioned :
struct data_t
{
int seq; // sequence number
int data [1024]; // user data
};
struct seqlock_t
{
data_t* current;
data_t pool [16]; // 16 user objects are held
};
seqlock_t sl;
write()
{
mtx.loñk();
data_t* d0 = sl.current; // load-consume
int idx = (sl.current - sl.pool + 1) % 16;
data_t* d = &sl.pool[idx];
d->seq += 1; // start writing new object
// store-store fence
modify(d0, d); // user processing
// store-store fence
d->seq += 1; // end writing new object
sl.current = d; // store-release
mtx.unloñk();
}
I don't understand the statement :
int idx = (sl.current - sl.pool + 1) % 16;
sl.current is a pointer , sl.pool is also a pointer , what I will get for
the result ?

No comments:

Post a Comment