про lock free stack
От: ioni Россия  
Дата: 22.01.08 10:02
Оценка:
В качестве тестовых экспериментов попробовал набросать реализацию
получилось вот что, но вот беда, при прогоне падает

в связи с этим вопрос это всегда так для lock free или я чего то упустил


#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <process.h>

//////////////////////////////////////////////////////////////////////////
bool is_work = true;

//////////////////////////////////////////////////////////////////////////
//compare and swap
bool cas(long* v, long cv, long nv)
{
    return (*v != InterlockedCompareExchange(v, nv, cv) );
}
//////////////////////////////////////////////////////////////////////////
template <class T>
class stack_lf
{
    struct node
    {
        node* next_;
        T value_;
    };
    volatile node* head_;
    //
    static node* make_empty_node()
    {
        node* n = new node();
        n->next_ = 0;
        n->value_ = 0;
        return n;
    }
    static void destroy_node(node volatile * n)
    {
        n->next_ = 0; n->value_ = 0;
        delete n, n = 0;
    }
    //
public:
    stack_lf() : head_( make_empty_node() )
    {
    }
    ~stack_lf()
    {
        volatile node* h = head_;
        while(h)
        {
            volatile node* n = h->next_;
            destroy_node(h);
            h = n;
        }
    }
    //
    void push(T v)
    {
        volatile node* next = make_empty_node();
        next->value_ = v;
        //
        do { next->next_ = head_->next_; } 
        while( !cas( (long*)&head_->next_, (long)next->next_, (long)next ) );
    }
    bool pop(T& val) 
    {
        volatile node* next = 0;
        do 
        { 
            next = head_->next_; 
            if(next == NULL)  { return false;  }
        } 
        while( !cas(((long*)(&(head_->next_))), ((long)next), ((long)(next->next_))) );
        //
        val = next->value_;
        destroy_node(next);
        return true;
    }
};
//////////////////////////////////////////////////////////////////////////
unsigned __stdcall pusher_thread(void* pv)
{
    stack_lf<long>* s = ( stack_lf<long>* )pv;
    long v = 1000;
    while( is_work )
    {
        printf("push value %d\n", v);
        s->push(v);
        ++v;        
    }
    return  0;
}

unsigned __stdcall poper_thread(void* pv)
{
    stack_lf<long>* s = ( stack_lf<long>* )pv;

    while( is_work )
    {
        long v;
        if( s->pop(v) )
        {
            printf("[0x%x] pop value %d\n", GetCurrentThreadId(), v);
        }
    }
    //////////////////////////////////////////////////////////////////////////
    // pop all elements
    long v;
    while( s->pop(v) )
    {
        printf("[0x%x] pop value %d\n", GetCurrentThreadId(), v);
    }

    //////////////////////////////////////////////////////////////////////////
    return  0;
}

int main()
{
    stack_lf<long> s;

    HANDLE hs0 = (HANDLE)_beginthreadex(NULL, 0, &pusher_thread, (void*)(&s), 0, NULL);
    HANDLE hs1 = (HANDLE)_beginthreadex(NULL, 0, &pusher_thread, (void*)(&s), 0, NULL);
    HANDLE hs2 = (HANDLE)_beginthreadex(NULL, 0, &poper_thread, (void*)(&s), 0, NULL);
    HANDLE hs3 = (HANDLE)_beginthreadex(NULL, 0, &poper_thread, (void*)(&s), 0, NULL);

    Sleep(100000);

    is_work = false;

    WaitForSingleObject(hs0, INFINITE);
    WaitForSingleObject(hs1, INFINITE);
    WaitForSingleObject(hs2, INFINITE);
    WaitForSingleObject(hs3, INFINITE);

    CloseHandle(hs0);
    CloseHandle(hs1);
    CloseHandle(hs2);
    CloseHandle(hs3);

    return 0;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.