Open MartinNowak opened 9 years ago
Hi @MartinNowak
Can you review this Lock-Free Stack implement is Safe ?
import core.atomic;
import std.stdio;
import std.traits;
shared struct AtomicStack(pNode, size_t next_offset) if( isPointer!(pNode) ) {
private {
@disable this(this) ;
alias Node = Unqual!(PointerTarget!(pNode)) ;
static assert( is(Node == struct)) ;
enum NullPtr = cast(shared(Node)*)0xdeadbeafdeadbeaf ;
static shared struct Link {
@disable this() ;
@disable this(this) ;
Node* m_next = void ;
}
Node* m_head = NullPtr ;
Link* getLink(shared(Node)* node) {
assert(node !is null) ;
return cast(Link*) (cast(void*)node + next_offset) ;
}
}
@property bool empty() const {
return m_head is NullPtr ;
}
@property shared(Node)* front(){
if( m_head is NullPtr ) {
return null ;
}
return m_head ;
}
void pushFront(shared(Node)* newNode) {
debug assert( getLink(newNode).m_next is null);
do {
getLink(newNode).m_next = m_head ;
} while (!cas( &m_head, getLink(newNode).m_next, newNode)) ;
}
shared(Node)* popFront() {
shared(Node)* node = void ;
do {
node = m_head ;
if( node is NullPtr ) {
return null ;
}
} while (!cas( &m_head, node, getLink(m_head).m_next)) ;
debug getLink(node).m_next = null ;
return node ;
}
}
struct Node {
int i = 10;
Node* next;
alias Stack = AtomicStack!(Node*, Node.init.next.offsetof);
this(int i) {
this.i = i;
}
}
static shared Node.Stack stack ;
void main(){
auto p = cast(shared(Node)*) new Node(3);
stack.pushFront(p);
writefln("p.i=%d", p.i);
p = cast(shared(Node)*) new Node(4);
stack.pushFront(p);
writefln("p.i=%d p.next.i=%d", p.i, p.next.i);
p = stack.popFront;
writefln("p.i=%d", p.i);
p = stack.popFront;
writefln("p.i=%d", p.i);
p = stack.popFront;
assert(p is null);
}
One example using cas SharedFreelist.