[m-dev.] Is this a semaphore bug or comprehension failure on my part?

Ralph Becket rbeck at microsoft.com
Tue May 15 00:30:16 AEST 2001


The code below does odd things:

%-----------------------------------------------------------------------
-------%
% philo3.m
% Ralph Becket <rbeck at microsoft.com>
% Mon May 14 14:32:29 BST 2001
% vim: ts=4 sw=4 et tw=0 wm=0 ff=unix ft=mercury
%
% The dining philosophers using semaphores.
%
%-----------------------------------------------------------------------
-------%

:- module philo3.

:- interface.

:- import_module io.



:- pred main(io__state::di, io__state::uo) is cc_multi.

%-----------------------------------------------------------------------
-------%
%-----------------------------------------------------------------------
-------%

:- implementation.

:- import_module string, list.
:- import_module semaphore, spawn.

%-----------------------------------------------------------------------
-------%

main -->
    semaphore__new(Fork0), semaphore__signal(Fork0),
    semaphore__new(Fork1), semaphore__signal(Fork1),
    semaphore__new(Fork2), semaphore__signal(Fork2),
    semaphore__new(Fork3), semaphore__signal(Fork3),
    semaphore__new(Fork4), semaphore__signal(Fork4),
    spawn(philosopher("Plato",      0, Fork0, 1, Fork1)),
    spawn(philosopher("Aristotle",  2, Fork2, 1, Fork1)),
    spawn(philosopher("Descartes",  2, Fork2, 3, Fork3)),
    spawn(philosopher("Calvin",     4, Fork4, 3, Fork3)),
          philosopher("Hobbes",     4, Fork4, 0, Fork0).



:- pred
philosopher(string,int,semaphore,int,semaphore,io__state,io__state).
:- mode philosopher(in, in, in, in, in, di, uo) is cc_multi.

philosopher(Name, A, SemA, B, SemB) -->

    io__format("%s is thinking\n", [s(Name)]),
    io__flush_output,
    rand_sleep(3),

    semaphore__wait(SemA),
    io__format("%s has acquired fork %d\n", [s(Name), i(A)]),
    io__flush_output,

    semaphore__wait(SemB),
    io__format("%s has acquired fork %d\n", [s(Name), i(B)]),
    io__flush_output,

    io__format("%s is eating\n", [s(Name)]),
    io__flush_output,
    rand_sleep(2),

    semaphore__signal(SemB),
    io__format("%s has relinquished fork %d\n", [s(Name), i(B)]),
    io__flush_output,

    semaphore__signal(SemA),
    io__format("%s has relinquished fork %d\n", [s(Name), i(A)]),
    io__flush_output,

    philosopher(Name, A, SemA, B, SemB).

%-----------------------------------------------------------------------
-------%

:- pred rand_sleep(int::in, io__state::di, io__state::uo) is det.
:- pragma c_code(rand_sleep(Int::in, IO0::di, IO::uo),
        [thread_safe, will_not_call_mercury], "{
    sleep(rand() % Int);
    IO =  IO0;
}").

%-----------------------------------------------------------------------
-------%
%-----------------------------------------------------------------------
-------%

It generates output like this:

Hobbes is thinking
Hobbes has acquired fork 4
Hobbes has acquired fork 0        <- (A) and
Hobbes is eating
Plato is thinking
Plato has acquired fork 0         <- (A) shouldn't be the case 
Plato has acquired fork 1         <- (B) and
Plato is eating
Aristotle is thinking
Aristotle has acquired fork 2
Aristotle has acquired fork 1     <- (B) shouldn't be the case
Aristotle is eating
Descartes is thinking
Calvin is thinking
Hobbes has relinquished fork 0
Plato has relinquished fork 1     <- (C) and
Aristotle has relinquished fork 1 <- (C) shouldn't be the case, etc...
Calvin has acquired fork 4
Calvin has acquired fork 3
Calvin is eating
Hobbes has relinquished fork 4
Hobbes is thinking
Plato has relinquished fork 0
Plato is thinking
Plato has acquired fork 0
Plato has acquired fork 1
Plato is eating

My understanding of semaphores is that they constitute mutexes
in the case where each semaphore counter can only be either 0 or 1.
>From what I can see, my code above does apply the 0/1 restriction,
yet the output is clearly wrong.

Have I misunderstood semaphores (pray God not, that would be
embarrassing) or is this a bug?

Another point is that if I recode main//0 as

main -->
    semaphore__new(Fork0), semaphore__signal(Fork0),
    semaphore__new(Fork1), semaphore__signal(Fork1),
    semaphore__new(Fork2), semaphore__signal(Fork2),
    semaphore__new(Fork3), semaphore__signal(Fork3),
    semaphore__new(Fork4), semaphore__signal(Fork4),
    spawn(philosopher("Plato",      0, Fork0, 1, Fork1)),
    spawn(philosopher("Aristotle",  2, Fork2, 1, Fork1)),
    spawn(philosopher("Descartes",  2, Fork2, 3, Fork3)),
    spawn(philosopher("Calvin",     4, Fork4, 3, Fork3)),
    spawn(philosopher("Hobbes",     4, Fork4, 0, Fork0)).

then the program terminates immediately, even though there are
runnable threads lying around.  Shurely shome mishtake?

Cheers,

Ralph

--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list