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++, you must name the source code file with .cpp as file extension and you must compile the program using C++ compiler --- g++ even though you may program in C. To compile a C++ program using g++, use the following syntax:

g++ -o executable_file source_code.cpp

3. Shared memory segments are identified by unique keys. A key is an unsigned integer. 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 a shared memory segment you need to use the following syntax:

Shared<DataType> pointer(size, key);

Where key is the key of the shared memory segment; size is the number of objects of data type DataType for which the requested memory segment should be allocated. When the statement is successfully executed, pointer points to the beginning of the allocated shared memory. When you access the shared memory, you may consider the data type of pointer is DataType *pointer;

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


//Program A

Shared<int> intPtr(5, 800);


//Program B

Shared<int> intPtr(5, 800);


In either program A or B, the following code segment would print: 200 --- 300

*intPtr = 200;

int *tmp = intPtr;

tmp = tmp + 1;

*tmp = 300;

Printf(“%d --- %d\n”, *intPtr, *tmp);

You can also access the shared memory as an array of objects of DataType. In this case, you can consider that pointer were declared as DataType pointer[size]. For the above example, you may use intPtr as an int array like the following example:

intPtr[0] = 100;

intPtr[1] = 200;

printf(“%d -- %d\n”, intPtr[0], intPtr[1]); // prints 100 -- 200

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<Node> 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. Thus, when they are no longer needed, the program (the process) must inform the kernel so that the kernel can detach them from the process. When no process is attached to them, the kernel would remove them from the system. To inform the kernel that a shard memory segment (or a semaphore) is no longer needed, the process should call the remove() operation of the shared memory segment (the semaphore). The following statements inform the kernel that the segment pointed by nodePtr and semaphore mutex are no longer needed.

nodePtr.remove();

mutex.remove();

6. If your program terminates abnormally and the remove operations are not be executed before the termination, the shared memory and segments may remain in the system even after all processes related to them have terminated. 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 lists the ID of each shared memory segment. These ID’s are used by kernel to internally identify memory segments. To remove a shared memory segment, we can the ipcrm command along with the internal ID of the segment. For example, to remove the two shared memory segments shown above, 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.