void*
?
Fork
and attaching shared
memory
Ftok
doesn't work for me
Due to a flaw in Solaris header files, you must declare the
semun
union yourself as follows:
union semun { int val; struct semid_ds *buf; ushort_t *array; };
Note that there is no name after the right curly brace. That defines the type but doesn't create a variable. You can then use it as follows:
union semun handyVariable;
For SETVAL
, the fourth argument to semctl
must be a thing of type
semun
. Thus, you have to define semun
(as
above) and then write:
union semun x; x.val = 1; semctl(mysem, 0, SETVAL, x);On a lot of machines, it would work just fine to write "1" in place of x. Not on Turing. On a SPARC, there's a huge difference between passing an integer and a union.
Thinking.
Q:Please correct me if I'm wrong, but it seems like, as a philosopher, we don't really need to enter mutual exclusion when changing our own state from thinking to hungry, because this transition really has nothing to do with putting down or snatching up a fork. So the two states are indistinguishable from the point of view of other philosophers looking for forks, and as long as the waiter enters mutual exclusion when reading the states, the output table should not be affected.
A: It does matter, because if the philosopher process reaches the critical section first then the waiter may still access the state array while the philosopher is updating his state. You don't want the waiter trying to read the state array while one of the philosophers is modifying it.
If the waiter uses a mutex, that does not prevent the philosopher from accessing data if the philosopher is not using a mutex. Semaphores only work if everyone is using them! That said, as long as the waiter only reads each entry in the state table once per print cycle, then the output should be fine as long as he uses a mutex to prevent the eating values from changing. The philosophers shouldn't need to use a mutex to change to the hungry state (although it wouldn't hurt)
You "probably' could get away with not using mutexes to control changing your own state from thinking to hungry, but:
Before you can use shared memory, you must create it with
shmget
. Note the similarity to semget
.
Also,
shmat
will return a pointer to the attached memory, but that memory
has no structure. You need to cast the return value to a pointer
corresponding to your data structure.
After that you can use the address returned as a pointer to a data
structure.
For example,
struct Mesg { // ... }; shmid = shmget(...) mesgptr = (Mesg *) shmat(shmid, (char *) 0, 0)Through
mesgptr
, the shared memory can now be used as a
structure, i.e.,
the structure you created to be shared.
void*
?Q: Is there a way to avoid the message ``warning: ANSI C++ forbids implicit conversion from 'void *' in argument passing'' when using the shared memory detach statement:
shmdt((void*) stuff);
A:
The compiler is
warning you that ANSI C++ won't convert your void*
to the
required char*
.
You should cast your stuff
variable to a
char*
instead of a void*
to get rid of the
warning.
The key thing to realize is that Solaris shared memory is getting
you an array of bytes, while your program is using a structure.
void*
is a generic pointer (an address without a type
associated with it).
They use it in the documentation because they don't know what kind of pointer
you'll be using. You can assign any pointer to
void*
, but you have to cast it when you assign the void*
to another pointer.
A void*
is a pointer to a memory area. You can treat it
as a buffer that
is castable to whatever type you'd like.
In the OS book, Tanenbaum creates a semaphore for each philosopher, but does not initialize them. You should probably initialize.
Fork
and attaching shared memoryShared memory does not need to be reattached by a child process if it has already been attached by the parent before the fork.
In Solaris, semaphores can be allocated as a group. for example, if you need 10 semaphores, you could ask for that number of semaphores to begin with. Thus, you might do something like the following:
philsems = semget(key, 5, IPC_CREAT | 0644)
The above statement creates 5 semaphores at once. You can manipulate
a particular semaphore by setting the sem_num
field in a
sembuf
argument to a
semop
call, or by setting the semnum
argument in a semctl
operation.
DO NOT attempt to manipulate more than one semaphore at a time
in a semop
or semctl
call. That will get
you into trouble. Stick to the simple version first.
In Solaris, you must pass a semaphore structure for a semaphore operation request.
semop
is the call:
semop(semid, address, numsems)where
semid
is your semaphore set id, as returned by
semget
(philsems
in the code above).
Address
is the address of the structure that contains the
operations
for each semaphore to be changed.
Numsems
is the number of entries in that structure.
Never use anything except 1 for numsems
.
The structure looks like this:
sem_num
is the number of the particular
semaphore to be manipulated, from 0 to N-1 if there are N
semaphores in the group.
sem_op
is the operation to perform on that
semaphore. You should never use anything except -1
(down) or 1 (up).
sem_flg
can specify a whole bunch of
options. For CS 110, you can just set it to zero.
Here is a more complete example:
// create a semaphore set with 5 semaphores philsems = semget(semkey, 5, IPC_CREAT | 0644) // ... // Up semaphore number 2 up(philsems, 2) // up() - V operation void up(int semset, int whichsem) { // structure to be sent struct sembuf sops; sops.sem_num = whichsem; sops.sem_op = 1; s.sem_flg = 0; semop(semset, &s, 1) }
The following pages are useful references for doing the dining philosphers project:
Note: The number in parentheses is the "section number" which represents which section of the printed manual contains the page in question. When viewing manual pages on Turing, you sometimes need to use the "-s" option to specify the desired section:
man -s 3c ftokOn Linux, the notation is a bit simpler:
man 3 ftok
You can use the "whatis" command to find out what sections contain pages with a particular name. If there's only one page with the name (as should be true for all pages above except intro) then you can leave out the section number. For all of you Linux & BSD users out there, note that the System V and Solaris versions of man require "-s" when you specify the section, unlike the GNU and BSD versions.
Also, if you wish to print a man page, you can use the "-t" flag. This will cause the output to go the printer as nicely formatted PostScript.
Ftok
Doesn't Work for MeQ: Ftok isn't working for me. It returns -1 regardless of how I set up the file and number inputs to it. How can I fix this? Thanks.
A:
You are probably calling ftok
with the name of a file
that doesn't exist.
The general approach for this kind of problem is to look at the
value of the global "errno
". An easy way to do that is
with strerror
.
For example:
#includeIf that doesn't make it clear, then look at the man page. The man page gives errors in terms of their abbreviations, such as#include // ... id = ftok(...); if (id == -1) { cerr << "ftok failed: " << strerror(errno) << endl; exit(1); }
ENOENT
. To
translate those into the
English used by strerror
, look in
/usr/include/sys/errno.h
. The comments in that
file are precisely the messages generated by strerror.
(Note: on Linux this file is named /usr/include/asm/errno.h
.)
Don't bother; it's too hard. Seriously invalid integers are usually
converted to
zero. (More accurately, they're converted to their integral
prefix.)
Just take the result of atoi
and check that for validity as if it
were
an integer -- i.e., if 0 is illegal, reject it, otherwise accept it
as
if it were 0.