Shared Memory and Semaphores

1. You must download the shared.h and semaphore.h from the class website into the subdirectory where you will compile your programs. These two files contain C++ classes that encapsulate the Unix system calls for shared memory and semaphores. 2. Insert the following two include statements in every program that uses shared memory and semaphores.

#include "shared.h" #include "semaphore.h"

Because the included files are in C++, your program must use .cpp as file extension even though you may program in C and you must compile the program using C++ compiler --- g++ like follows:

g++ -o executable_file source_code.cpp

3. Programs may share multiple segments with each other. At application level, shared memory segments are identified by keys. A key is an unsigned integer value. When program A and program B want to share a memory segment, they use the same key to inform the kernel that they want that shared memory segment. To declare shared memory you need to use the following syntax:

Shared pointer(size, key);

Where key is the identifier of the shared memory segment; size is the number of objects of DataType for which the requested memory segment should be allocated. DataType specifies the data type of the objects to be allocated in the shared memory. When the statement is successfully executed, pointer points to the beginning of the shared memory allocated.

For example, programs A and B want to share a memory segment for five integers (int type) with key 800, you can write the two programs for this shared memory as follows

//Program A //Program B

Shared intPtr(5, 800); Shared intPtr(5, 800);

The other way to access the shared memory is to treat it as an array of objects of DataType. You can access the five integers in the following two ways. You may use intPtr as an int pointer like the following example:

intPtr[0] = 100; intPtr[1] = 200; printf(“third integer: %d\n”, intPtr[2]);

You may also request shared memory for user-defined structures. For example, you may define:

typedef struct NODE { int x; float y; char z; } Node;

To request a shared memory segment for 12 objects of Node with key value 803, Shared nodePtr(12, 803);

Now we can access the shared memory through pointers or an array as follows:

By pointer: nodePtr->x = 200; // modify the first Node nodePtr->y = 200.2; nodePtr->z = 'c';

nodePtr++; nodePtr->x = 300; // modify the second Node ....

By array:

nodePtr[0].x = 400; // modify the first Node nodePtr[0].y = 100.2; nodePtr[0].z = 'b';

nodePtr[1].x = 500; // modify the second Node nodePtr[1].y = 700.2; nodePtr[1].z = 'g';

4. Programs can share semaphores as well. Like shared memory segments, semaphores are identified with keys and a key is an integer. When two programs wish to use the same semaphore, they request a semaphore from the kernel using the same key value. To request a semaphore,

Semaphore sema_name(value, key);

where key is the key value you use in different programs for the same semaphore; value is the initial value of the semaphore. For example to declare a mutex with initial value 1 and key value 800, you would write:

Semaphore mutex(1, 800);

to declare availSlot with initial value 5 and key value 801, and availItems with initial value 0 and key 802 you may write:

Semaphore availSlot(5, 801); Semaphore availItem(0, 802);

Now you may use the up() and down() operations (or wait() and signal()) to manipulate the semaphores. For the down() and up() operations, use wait() and signal() to replace them, respectively. For example for the producer of the producer and consumer problem, you may code:

availSlot.wait(); mutex.wait(); // deposit the item mutex.signal(); availItem.signal();

5. Both shared memory segments and semaphores are system resources and those resources are automatically release by the kernel when programs who requested them terminate. The kernel must be explicitly informed to release individual shared memory segments and semaphores. To request the kernel to release a shared segment (or semaphore), you can the remove operation. For example,

nodePtr.remove(); mutex.remove();

6. If your program terminates abnormally, the remove operations may not be executed before the termination. When that happens, you can remove or release those resource manually using Unix IPC commands.

You can use command ipcs to list all shared memory segments and semaphores (and also messages, which are not used in this assignment) on the computer.

ipcs

The command would generate output as shows below:

%ipcs Message Queues: T ID KEY MODE OWNER GROUP

Shared Memory: T ID KEY MODE OWNER GROUP m 655360 801 --rwarwarwa bi 110 m 655361 800 --rwarwarwa bi 110

Semaphores: T ID KEY MODE OWNER GROUP s 720896 800 --rwarwarwa bi 110 s 720897 801 --rwarwarwa bi 110 s 720898 802 --rwarwarwa bi 110

It shows that there are two shared memory segments and three semaphores and the owner those is user bi.

The second column in all displays contains the ID that is used by the kernel to identify each resource. Recall that at application level, we use a key to identify each resource. To use the ipcrm command to remove those resources, we need to use this ID, not the key.

For example, to remove the two shared memory segments, at shell prompt, type

To remove the two shared memory segments, type

ipcrm -m 655360 -m 655361

To remove the first two semaphores,

ipcrm -s 720896 -s 720897

When there are many shared memory segments and /or semaphores left behind by users, the system suffers in performance. For this reason, it is required to remove all your shared memory and semaphore before you log out. If any shared memory or semaphore found when you are not logging in, points will be deducted.