Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
yet another (tiny) implementation of condvars
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  15 messages - Collapse all  -  Translate all to Translated (View all originals)
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Michael Podolsky  
View profile  
 More options Sep 30 2010, 1:33 pm
Newsgroups: comp.programming.threads
From: Michael Podolsky <michael.podolsky...@gmail.com>
Date: Thu, 30 Sep 2010 10:33:31 -0700 (PDT)
Local: Thurs, Sep 30 2010 1:33 pm
Subject: yet another (tiny) implementation of condvars
If you are not already bored with this recurring subject,
here is my very compact implementation of condvars based on
semaphores.

Of course, I am interested in feedbacks.

condvar constructor:
{
waiters : int(0)
task : int(0)
turn1 : semaphore(1) // one is open (original sem value = 1)
turn2 : semaphore(0) // another is closed
m: mutex

}

wait(mutex CS)
{
   turn1.get();
     m.lock();
     ++waiters;
     m.unlock();
   turn1.put();

   CS.unlock();

   turn2.get();
     m.lock();
        bool last = (--waiters == task);
     m.unlock();
   if(last)
       turn1.put();
   else
       turn2.put();

   CS.lock();

}

signal(bool all)
{
   turn1.get();
   m.lock();
   if(waiters)
   {
       if(all)
            task = 0;
       else
            task = waiters-1;
       m.unlock();
       turn2.put();
   }
   else
   {
       m.unlock();
       turn1.put();
   }

}

Thanks, Michael

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Chris M. Thomasson  
View profile  
 More options Sep 30 2010, 11:26 pm
Newsgroups: comp.programming.threads
From: "Chris M. Thomasson" <cris...@charter.net>
Date: Thu, 30 Sep 2010 20:26:27 -0700
Local: Thurs, Sep 30 2010 11:26 pm
Subject: Re: yet another (tiny) implementation of condvars
"Michael Podolsky" <michael.podolsky...@gmail.com> wrote in message

news:53a28afc-cc6f-4ef5-a44b-ce47254b4577@x42g2000yqx.googlegroups.com...

> If you are not already bored with this recurring subject,
> here is my very compact implementation of condvars based on
> semaphores.

> Of course, I am interested in feedbacks.

I need to take a look at it Michael; I will probably implement it in Relacy
Race Detector when I get some time. FWIW, here is a simple and correct
condition variable in Windows, it's broadcast only, but that is definitely
allowed for in the POSIX standard:

<pseudo-code sketch>
___________________________________________________________
struct condvar
{
    struct waitset
    {
        HANDLE m_event; // = manual reset event; set to false
        LONG m_refs; // = 0
    };

    waitset* m_waitset; // = NULL
    LONG m_refs; // = 0
    CRITICAL_SECTION m_mutex;

    bool timed_wait(LPCRITICAL_SECTION umutex, DWORD tout)
    {
        // grab a reference to the current waitset
        EnterCriticalSection(&m_mutex);
        waitset* w = m_waitset;
        if (! w) w = m_waitset = new waitset();
        ++m_refs;
        LeaveCriticalSection(&m_mutex);

        // unlock user mutex and wait on the waitset we obtained
        LeaveCriticalSection(umutex);
        DWORD status = WaitForSingleObject(w->m_waitset, tout);

        // decrement our waitsets refcount
        if (! InterlockedDecrement(&w->m_refs))
        {
            delete w;
        }

        EnterCriticalSection(umutex);

        // that's all folks!  ;^)

        return status == WAIT_OBJECT_0 ? true : false;
    }

    void wait(LPCRITICAL_SECTION umutex)
    {
        timed_wait(umutex, INFINITE);
    }

    void broadcast()
    {
        // swap a reference to the current waitset with NULL
        EnterCriticalSection(&m_mutex);
        waitset* w = m_waitset;
        LONG refs = m_refs;
        m_waitset = NULL;
        m_refs = 0;
        LeaveCriticalSection(&m_mutex);

        if (w)
        {
            // signal all waiters
            SetEvent(w->m_event);

            // transfer the swapped reference count to the
            // waitset reference count
            if (InterlockedExchangeAdd(&w->m_refs, refs) == -refs)
            {
                delete w;
            }
        }
    }

    void signal()
    {
        broadcast();
    }

};

_____________________________________________________________

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Chris M. Thomasson  
View profile  
 More options Sep 30 2010, 11:26 pm
Newsgroups: comp.programming.threads
From: "Chris M. Thomasson" <cris...@charter.net>
Date: Thu, 30 Sep 2010 20:26:27 -0700
Local: Thurs, Sep 30 2010 11:26 pm
Subject: Re: yet another (tiny) implementation of condvars
"Michael Podolsky" <michael.podolsky...@gmail.com> wrote in message

news:53a28afc-cc6f-4ef5-a44b-ce47254b4577@x42g2000yqx.googlegroups.com...

> If you are not already bored with this recurring subject,
> here is my very compact implementation of condvars based on
> semaphores.

> Of course, I am interested in feedbacks.

I need to take a look at it Michael; I will probably implement it in Relacy
Race Detector when I get some time. FWIW, here is a simple and correct
condition variable in Windows, it's broadcast only, but that is definitely
allowed for in the POSIX standard:

<pseudo-code sketch>
___________________________________________________________
struct condvar
{
    struct waitset
    {
        HANDLE m_event; // = manual reset event; set to false
        LONG m_refs; // = 0
    };

    waitset* m_waitset; // = NULL
    LONG m_refs; // = 0
    CRITICAL_SECTION m_mutex;

    bool timed_wait(LPCRITICAL_SECTION umutex, DWORD tout)
    {
        // grab a reference to the current waitset
        EnterCriticalSection(&m_mutex);
        waitset* w = m_waitset;
        if (! w) w = m_waitset = new waitset();
        ++m_refs;
        LeaveCriticalSection(&m_mutex);

        // unlock user mutex and wait on the waitset we obtained
        LeaveCriticalSection(umutex);
        DWORD status = WaitForSingleObject(w->m_waitset, tout);

        // decrement our waitsets refcount
        if (! InterlockedDecrement(&w->m_refs))
        {
            delete w;
        }

        EnterCriticalSection(umutex);

        // that's all folks!  ;^)

        return status == WAIT_OBJECT_0 ? true : false;
    }

    void wait(LPCRITICAL_SECTION umutex)
    {
        timed_wait(umutex, INFINITE);
    }

    void broadcast()
    {
        // swap a reference to the current waitset with NULL
        EnterCriticalSection(&m_mutex);
        waitset* w = m_waitset;
        LONG refs = m_refs;
        m_waitset = NULL;
        m_refs = 0;
        LeaveCriticalSection(&m_mutex);

        if (w)
        {
            // signal all waiters
            SetEvent(w->m_event);

            // transfer the swapped reference count to the
            // waitset reference count
            if (InterlockedExchangeAdd(&w->m_refs, refs) == -refs)
            {
                delete w;
            }
        }
    }

    void signal()
    {
        broadcast();
    }

};

_____________________________________________________________

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Chris M. Thomasson  
View profile  
 More options Oct 3 2010, 11:33 pm
Newsgroups: comp.programming.threads
From: "Chris M. Thomasson" <cris...@charter.net>
Date: Sun, 3 Oct 2010 20:33:45 -0700
Local: Sun, Oct 3 2010 11:33 pm
Subject: Re: yet another (tiny) implementation of condvars
"Michael Podolsky" <michael.podolsky...@gmail.com> wrote in message

news:53a28afc-cc6f-4ef5-a44b-ce47254b4577@x42g2000yqx.googlegroups.com...

[...]

I must be missing something important here, but does the logic above
actually broadcast? I mean, you only seem to be incrementing the semaphore
one single time... How does that wake multiple waiters? I am confused here!

;^(...


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Chris M. Thomasson  
View profile  
 More options Oct 3 2010, 11:37 pm
Newsgroups: comp.programming.threads
From: "Chris M. Thomasson" <cris...@charter.net>
Date: Sun, 3 Oct 2010 20:37:36 -0700
Local: Sun, Oct 3 2010 11:37 pm
Subject: Re: yet another (tiny) implementation of condvars
"Chris M. Thomasson" <cris...@charter.net> wrote in message
news:eWbqo.1140$HW3.411@newsfe11.iad...

> "Michael Podolsky" <michael.podolsky...@gmail.com> wrote in message
> news:53a28afc-cc6f-4ef5-a44b-ce47254b4577@x42g2000yqx.googlegroups.com...
>> If you are not already bored with this recurring subject,
>> here is my very compact implementation of condvars based on
>> semaphores.

>> Of course, I am interested in feedbacks.
[...]
> I must be missing something important here, but does the logic above
> actually broadcast? I mean, you only seem to be incrementing the semaphore
> one single time... How does that wake multiple waiters? I am confused
> here!

> ;^(...

Ahh. It seems like you "continue" to increment the semaphore in the
following waiting logic:
___________________________________
   turn2.get();
     m.lock();
        bool last = (--waiters == task);
     m.unlock();
   if(last)
       turn1.put();
   else
       turn2.put();
___________________________________

Okay. I still need to impl this in Relacy, but I think I see what you are
getting at here Michael.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Michael Podolsky  
View profile  
 More options Oct 4 2010, 6:45 pm
Newsgroups: comp.programming.threads
From: Michael Podolsky <michael.podolsky...@gmail.com>
Date: Mon, 4 Oct 2010 15:45:59 -0700 (PDT)
Local: Mon, Oct 4 2010 6:45 pm
Subject: Re: yet another (tiny) implementation of condvars
On Sep 30, 11:26 pm, "Chris M. Thomasson" <cris...@charter.net> wrote:

BTW, as for your implementation, I could not figure out why you
collect the waiters number in condvar::m_refs and not directly in
waitset::m_refs. Then there comes a trick of transferring
condvar::m_refs to waitset::m_refs. Well, it should work, but I could
not understand why you needed to maintain two separate counters at all
and not worked directly on waitset::m_refs. Could you please clarify?

Thanks, Michael


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Chris M. Thomasson  
View profile  
 More options Oct 6 2010, 4:33 pm
Newsgroups: comp.programming.threads
From: "Chris M. Thomasson" <cris...@charter.net>
Date: Wed, 6 Oct 2010 13:33:51 -0700
Local: Wed, Oct 6 2010 4:33 pm
Subject: Re: yet another (tiny) implementation of condvars

> "Michael Podolsky" <michael.podolsky...@gmail.com> wrote in message
> news:58035933-7006-479e-a94e-d3f618a29bee@d25g2000yqc.googlegroups.com...
> > On Sep 30, 11:26 pm, "Chris M. Thomasson" <cris...@charter.net> wrote:
> > void broadcast()
> > {
    [...]
> > }
> BTW, as for your implementation, I could not figure out why you
> collect the waiters number in condvar::m_refs and not directly in
> waitset::m_refs. Then there comes a trick of transferring
> condvar::m_refs to waitset::m_refs. Well, it should work, but I could
> not understand why you needed to maintain two separate counters at all
> and not worked directly on waitset::m_refs. Could you please clarify?

I did it to avoid locking the `condvar::m_mutex' after a waiter wakes.
Although, I think I might be able to use a single reference count and still
avoid locking the `condvar::m_mutex'. Humm... Perhaps something like:

<pseudo-code sketch>
___________________________________________________________
struct condvar
{
    struct waitset
    {
        HANDLE m_event; // = manual reset event; set to false
        LONG m_refs; // = 1
    };

    waitset* m_waitset; // = NULL
    CRITICAL_SECTION m_mutex;

    bool timed_wait(LPCRITICAL_SECTION umutex, DWORD tout)
    {
        // grab a reference to the current waitset
        EnterCriticalSection(&m_mutex);
        waitset* w = m_waitset;
        if (! w) w = m_waitset = new waitset();
        InterlockedIncrement(&w->m_refs);
        LeaveCriticalSection(&m_mutex);

        // unlock user mutex and wait on the waitset we obtained
        LeaveCriticalSection(umutex);
        DWORD status = WaitForSingleObject(w->m_waitset, tout);

        // decrement our waitsets refcount
        if (! InterlockedDecrement(&w->m_refs))
        {
            delete w;
        }

        EnterCriticalSection(umutex);

        // that's all folks!  ;^)

        return status == WAIT_OBJECT_0 ? true : false;
    }

    void wait(LPCRITICAL_SECTION umutex)
    {
        timed_wait(umutex, INFINITE);
    }

    void broadcast()
    {
        // swap a reference to the current waitset with NULL
        EnterCriticalSection(&m_mutex);
        waitset* w = m_waitset;
        m_waitset = NULL;
        LeaveCriticalSection(&m_mutex);

        if (w)
        {
            // signal all waiters
            SetEvent(w->m_event);

            // decrement our waitsets refcount
            if (! InterlockedDecrement(&w->m_refs))
            {
                delete w;
            }
        }
    }

    void signal()
    {
        broadcast();
    }

};

_____________________________________________________________

What do you think?


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Chris M. Thomasson  
View profile  
 More options Oct 6 2010, 11:05 pm
Newsgroups: comp.programming.threads
From: "Chris M. Thomasson" <cris...@charter.net>
Date: Wed, 6 Oct 2010 20:05:11 -0700
Local: Wed, Oct 6 2010 11:05 pm
Subject: Re: yet another (tiny) implementation of condvars
"Michael Podolsky" <michael.podolsky...@gmail.com> wrote in message

news:53a28afc-cc6f-4ef5-a44b-ce47254b4577@x42g2000yqx.googlegroups.com...
> If you are not already bored with this recurring subject,
> here is my very compact implementation of condvars based on
> semaphores.

> Of course, I am interested in feedbacks.

[...]

I went ahead and implemented your algorithm in Relacy Race Detector 2.3:

http://cpt.pastebin.com/uhcAg5Km

http://groups.google.com/group/relacy

It's working great.

:^)


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Michael Podolsky  
View profile  
 More options Oct 8 2010, 3:10 pm
Newsgroups: comp.programming.threads
From: Michael Podolsky <michael.podolsky...@gmail.com>
Date: Fri, 8 Oct 2010 12:10:44 -0700 (PDT)
Local: Fri, Oct 8 2010 3:10 pm
Subject: Re: yet another (tiny) implementation of condvars
On Oct 6, 4:33 pm, "Chris M. Thomasson" <cris...@charter.net> wrote:

> > "Michael Podolsky" <michael.podolsky...@gmail.com> wrote in message
> > BTW, as for your implementation, I could not figure out why you
> > collect the waiters number in condvar::m_refs and not directly in
> > waitset::m_refs. Then there comes a trick of transferring
> > condvar::m_refs to waitset::m_refs. Well, it should work, but I could
> > not understand why you needed to maintain two separate counters at all
> > and not worked directly on waitset::m_refs. Could you please clarify?

> I did it to avoid locking the `condvar::m_mutex' after a waiter wakes.
> Although, I think I might be able to use a single reference count and still
> avoid locking the `condvar::m_mutex'. Humm... Perhaps something like:

> <pseudo-code sketch>
> What do you think?

Looks good for me. Apart from decrementing refcount and deleting a
waitset in broadcast.
I would just wipe out the following part of your code:

>     void broadcast()
>     {
...

>             // decrement our waitsets refcount
>             if (! InterlockedDecrement(&w->m_refs))
>             {
>                 delete w;
>             }
...
>     }

Thanks, Michael

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Michael Podolsky  
View profile  
 More options Oct 8 2010, 3:16 pm
Newsgroups: comp.programming.threads
From: Michael Podolsky <michael.podolsky...@gmail.com>
Date: Fri, 8 Oct 2010 12:16:48 -0700 (PDT)
Local: Fri, Oct 8 2010 3:16 pm
Subject: Re: yet another (tiny) implementation of condvars

Oh, it is just an 'academic' exercise, I do not mean to use it in a
real application. It has too many problems. I am working now on a,
hopefully, much better implementation (still with only a couple of
semaphores for it's still an 'academic' task for me).

BTW, what do you mean by  "implemented it in Relacy"? You did not make
it a part of Relacy, did you? What then?

Thanks, Michael


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Chris M. Thomasson  
View profile  
 More options Oct 9 2010, 8:32 pm
Newsgroups: comp.programming.threads
From: "Chris M. Thomasson" <cris...@charter.net>
Date: Sat, 9 Oct 2010 17:32:53 -0700
Local: Sat, Oct 9 2010 8:32 pm
Subject: Re: yet another (tiny) implementation of condvars
"Michael Podolsky" <michael.podolsky...@gmail.com> wrote in message

news:8dade1f9-f288-4722-8b57-a1ac37786d60@h7g2000yqn.googlegroups.com...

What did you have in mind? I need to decrement the reference count here in
order to determine when a waitset can be safely destroyed/reused.

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Chris M. Thomasson  
View profile  
 More options Oct 11 2010, 2:39 am
Newsgroups: comp.programming.threads
From: "Chris M. Thomasson" <cris...@charter.net>
Date: Sun, 10 Oct 2010 23:39:10 -0700
Local: Mon, Oct 11 2010 2:39 am
Subject: Re: yet another (tiny) implementation of condvars
"Michael Podolsky" <michael.podolsky...@gmail.com> wrote in message

news:e90172c7-7183-486d-9d1b-8ad423eaff49@d17g2000yqm.googlegroups.com...
[...]

> BTW, what do you mean by  "implemented it in Relacy"? You did not make
> it a part of Relacy, did you? What then?

I probably should have written:

I implemented your condvar algorithm using the API's provided by Relacy.

Sorry for any confusion!

;^(


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Michael Podolsky  
View profile  
 More options Oct 18 2010, 1:21 pm
Newsgroups: comp.programming.threads
From: Michael Podolsky <michael.podolsky...@gmail.com>
Date: Mon, 18 Oct 2010 10:21:03 -0700 (PDT)
Local: Mon, Oct 18 2010 1:21 pm
Subject: Re: yet another (tiny) implementation of condvars
On Oct 9, 8:32 pm, "Chris M. Thomasson" <cris...@charter.net> wrote:

I meant in your last version of the code, you should decrement and
delete inside 'timed_wait' function only.
Otherwise you have N+1 InterlockedDecrements (N inside 'timed_wait and
one inside 'broadcast')
and may delete your waitset too soon, then access it again with last
decrement which leads to GPF or memory corruption.
Ain't I right?

Regards, Michael
(Late answer, sorry)


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Chris M. Thomasson  
View profile  
 More options Oct 18 2010, 7:01 pm
Newsgroups: comp.programming.threads
From: "Chris M. Thomasson" <cris...@charter.net>
Date: Mon, 18 Oct 2010 16:01:40 -0700
Local: Mon, Oct 18 2010 7:01 pm
Subject: Re: yet another (tiny) implementation of condvars
"Michael Podolsky" <michael.podolsky...@gmail.com> wrote in message

news:5e809343-83ee-4d12-b7ec-7362d4f817d1@e14g2000yqe.googlegroups.com...
On Oct 9, 8:32 pm, "Chris M. Thomasson" <cris...@charter.net> wrote:
[...]

> > What did you have in mind? I need to decrement the reference count here
> > in
> > order to determine when a waitset can be safely destroyed/reused.
> I meant in your last version of the code, you should decrement and
> delete inside 'timed_wait' function only.
> Otherwise you have N+1 InterlockedDecrements (N inside 'timed_wait and
> one inside 'broadcast')

Take note of the following snippet:
_____________________________________________________
    struct waitset
    {
        HANDLE m_event; // = manual reset event; set to false
        LONG m_refs; // = 1
    };

    waitset* m_waitset; // = NULL
    CRITICAL_SECTION m_mutex;

    bool timed_wait(LPCRITICAL_SECTION umutex, DWORD tout)
    {
        // grab a reference to the current waitset
        EnterCriticalSection(&m_mutex);
        waitset* w = m_waitset;
        if (! w) w = m_waitset = new waitset();
        InterlockedIncrement(&w->m_refs);
        LeaveCriticalSection(&m_mutex);

        [...]
    }
_____________________________________________________

Okay, a new waitset has always has a reference count of 1. When a waiter
_creates_ a new waitset, or references a current waitset, it always does an
atomic increment _within_ the critical section. Therefore if there are N
waiters, the reference count will always be 1 greater than N before a
broadcast occurs. Therefore, I think that the scenario you describe cannot
happen.

Let's say there are 3 waiters; the refcount will be 4. Now, 1 waiter times
out, thus rendering the refcount to 3. A broadcast occurs, thus rendering
the refcount to 2. Finally the last two waiters wake and perform decrements,
thus rendering the refcount to zero. This seems safe to me...

> and may delete your waitset too soon, then access it again with last
> decrement which leads to GPF or memory corruption.
> Ain't I right?

I am having trouble coming up with a scenario in which a waitset can be
destroyed too soon...

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Michael Podolsky  
View profile  
 More options Oct 19 2010, 10:19 am
Newsgroups: comp.programming.threads
From: Michael Podolsky <michael.podolsky...@gmail.com>
Date: Tue, 19 Oct 2010 07:19:36 -0700 (PDT)
Local: Tues, Oct 19 2010 10:19 am
Subject: Re: yet another (tiny) implementation of condvars
Oh, sorry, I did not notice you create your waiter object with
starting ref count = 1.
i thought it was zero.

You are right.

Thanks, Michael


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
End of messages
« Back to Discussions « Newer topic     Older topic »