Linux Process
Synchronization
• Tanenbaum 10.3, 2.3
• Linux man pthread_mutex_init, etc.
• The Linux Programming Interface - Kerrisk
• Interprocess Communications in Linux - Gray
cs431-cotter
1
Overview
•
•
•
•
•
•
•
•
•
Linux IPC
Signal
Alarm
Wait
Semaphore (named and unnamed)
Mutex
Pipe ( named and unnamed)
Messages
Shared Memory
cs431-cotter
cs431-cotter
2
Linux IPC
• Kernel Synchronization
– Use wait_queue for kernel process sync
– Allows multiple processes to wait for a single event
– Serves as basic component to build user process
sync
• Process synchronization
–
–
–
–
Signal - most primitive
Semaphore
Pipes
etc.
cs431-cotter
3
Signals in Linux
Figure 10-5. The signals required by POSIX.
cs431-cotter
Tanenbaum, Modern Operating Systems 3 e, (c) 2008 Prentice-Hall, Inc. All rights reserved. 0-13-6006639
4
Signals
1) SIGHUP
2) SIGINT
3) SIGQUIT
4) SIGILL
5) SIGTRAP
6) SIGABRT
7) SIGEMT
8) SIGFPE
9) SIGKILL
10) SIGBUS
11) SIGSEGV
12) SIGSYS
13) SIGPIPE
14) SIGALRM
15) SIGTERM
16) SIGURG
17) SIGSTOP
18) SIGTSTP
19) SIGCONT
20) SIGCHLD
21) SIGTTIN
22) SIGTTOU
23) SIGIO
24) SIGXCPU
25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF
29) SIGINFO
30) SIGUSR1
28) SIGWINCH
31) SIGUSR2
Current versions of Linux support 64 signals (real time
signals added).
See: man 2 signal, man 2 sigaction man 7 signal
cs431-cotter
5
Signal Handler
• Signal function can have different behavior based
on the version of UNIX.
• sigaction (signal_to_catch, new_action, old_action)
• struct sigaction {
void * sa_handler; // What function do we call?
sigset_t mask;
// Mask of signals to block when called
int sa_flags;
// Special flags to set.
};
cs431-cotter
6
Alarm
• Allows user program to set an external
timer (measured in seconds).
• If alarm times out, sigalrm will be sent to
the calling process.
• Use: sigaction (SIGALRM, sigaction,
NULL);
cs431-cotter
7
Sig_alarm.cpp
#include <iostream>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
#define MAXLINE 128
static void sig_alarm(int signo);
int main ()
{
int n;
char line [MAXLINE];
struct sigaction act;
memset (&act, 0, sizeof(act));
act.sa_handler = &sig_alarm;
act.sa_flags = SA_RESTART;
cs431-cotter
8
Sig_alarm.cpp
if ((sigaction(SIGALRM, &act, NULL)) < 0)
{
cout <<"The sigact function returned an error" <<
endl;
exit (1);
}
alarm (5);
if ( cin.getline(line, MAXLINE) < 0) {
cout << "cin returned an error" << endl;
exit(1);
}
alarm(0);
cout << line << endl;
exit(0);
}
static void sig_alarm(int signo) {
cout << " ### We got the alarm signal!! ###" << endl;
}
cs431-cotter
9
sig_alarm.cpp Output
[rcotter@kc-sce-450p2 cs431]$ g++ -o sigtest sig_alarm3.cpp
[rcotter@kc-sce-450p2 cs431]$ ./sigtest
This is a test
This is a test
[rcotter@kc-sce-450p2 cs431]$ ./sigtest
This is another ### We got the alarm signal!! ###
test
This is another test
[rcotter@kc-sce-450p2 cs431]$
cs431-cotter
10
wait( )
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait (int *status);
•
The wait function suspends execution of the
current pro
cess until a child has exited, or
until a signal is deliv
ered whose action is
to terminate the current process or
to call a
signal handling function.
If a child has
already exited by the time of the call (a so-called
"zom
bie" process), the function returns
immediately. Any sys
tem resources used by the
child are freed.
cs431-cotter
11
waittest1.c
#include
#include
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<string.h>
<unistd.h>
<sys/types.h>
<sys/wait.h>
int main()
{
pid_t
pid;
int status;
printf("Forking child process...\n");
if ((pid = fork()) < 0)
{
printf("fork failed!\n");
exit(1);
}
cs431-cotter
12
waittest1.c
{
/* child process */
else if (pid == 0)
sleep(5);
printf("Child process is shutting down\n");
exit(7);
}
else {
/* parent process */
if (wait (&status) != pid)
{
printf("Wait returned invalid pid\n");
exit(1);
}
if (WIFEXITED(status))
printf("Normal Termination. Exit value %2d\n",
WEXITSTATUS(status));
else
{
printf("Abnormal termination!!!\n");
exit(1);
}
printf("Parent shutting down...\n");
exit(0);
}
}
cs431-cotter
13
waittest.c output
rcotter@debian-alpha:~$ gcc -o waittest
waittest1.c
rcotter@debian-alpha:~$ ./waittest
Forking child process...
Child process is shutting down
Normal Termination. Exit value
7
Parent shutting down...
rcotter@debian-alpha:~$
cs431-cotter
14
Semaphores
• POSIX version of semaphores
– #include <semaphore.h>
– classic semaphore implementation
• System V version of semaphores
– #include <sys/sem.h>
– Enhanced version of semaphores to include
sets
cs431-cotter
15
POSIX (unnamed) Semaphores
• sem_t empty, full;
• int sem_init ((sem_t *sem, int pshared,
unsigned int value));
– sem_t (address of semaphore to be initialized
– pshared (is semaphore shared?) SHARED, 0
– initial value
• int sem_wait ((sem_t *sem));
– sem_t (address of semaphore to be waited for)
• int sem_post ((sem_t *sem));
– sem_t (address of semaphore to be signalled)
cs431-cotter
16
Example Semaphore fragment
sem_t checker;
Main Program {
declare variables...
sem_init(&checker, 0, 1);
pthread_create(&pid1, NULL, job, NULL);
pthread_create(&pid2, NULL, job, NULL);
pthread_join(pid1, NULL);
pthread_join(pid2, NULL);
:
}
job() {
while (work to do..)
{
sem_wait (&checker);
do stuff...
sem_post(&checker);
do other stuff....
}
cs431-cotter
}
17
POSIX Named Semaphores
• sem_t empty, full;
• sem_t *sem_open (char *name, int oflag,
[mode_t mode[, [int init_value]);
–
–
–
–
char *name (must begin with “/”)
[O_CREAT], [O_EXCL], 0 (new or existing semaphore?)
mode (if new, mod bits 0xxx)
Init_value (if new, initial value of semaphore)
• int sem_wait ((sem_t *sem));
– sem_t (address of semaphore to be waited for)
• int sem_post ((sem_t *sem));
– sem_t (address of semaphore to be signalled)
•
•
•
•
int sem_close (sem_t *sem);
int sem_unlink(char *name);
int sem_getvalue (sem_t *sem, int *val);
Named semaphore has kernel persistence
– Created in /dev/shm
cs431-cotter
18
18
Named Semaphore example
producer - Consumer
#define SHARED 0
#define BUFSIZE 20
int terminatethreads=0;
void *Producer(void *); /* the two threads */
void *Consumer(void *);
sem_t *Sempty, *Sfull, *Sflag; /* the semaphore descriptors */
char sem1[] = "/semEmpty"; //The names for the semaphores
char sem2[] = "/semFull";
char sem3[] = "/semFlag";
int buf[BUFSIZE]; /* shared buffer
*/
int mycount;
static void sig_alarm(int signo);
19
Named Semaphore example
int main(int argc, char *argv[])
int ans;
time_t now;
pthread_t pid, cid;
{
time (&now);
srand (now);
if (signal (SIGALRM, sig_alarm) == SIG_ERR)
{
cout << "The signal function returned an error" << endl;
exit (1);
}
//Here we set the alarm to specified seconds.
alarm (atoi(argv[1]));
cout << “Alarm set. Now for semaphores" << endl;
Sflag = sem_open (sem3, O_CREAT, 660, 1);
Sfull = sem_open (sem2, O_CREAT, 660, 0);
Sempty = sem_open (sem1, O_CREAT, 660, BUFSIZE);
mycount = 0;
20
Named Semaphore example
cout << "main started" << endl;
pthread_create(&pid, 0, Producer, NULL);
pthread_create(&cid, 0, Consumer, NULL);
cout << "Created both threads" << endl;
pthread_join(pid, NULL);
pthread_join(cid, NULL);
cout << "The number of items still in the buffer is " << mycount << endl;
sem_getvalue(Sfull, &ans);
cout << “The value of Sfull is “ << ans << endl;
sem_close(Sflag);
sem_close(Sfull);
sem_close(Sempty);
sem_unlink(sem1);
sem_unlink(sem2);
sem_unlink(sem3);
cout << "Main done\n" << endl;
return 0;
}
21
Named Semaphore example
void *Producer(void *arg) {
int produced=0;
int input = 0;
cout << "\nProducer created.." << endl;
while(!terminatethreads)
{
sem_wait(Sempty); //Decrements 'empty'
produced++;
input = (input + 1) % BUFSIZE;
sem_wait(Sflag);
buf[input] = produced;
mycount++;
sem_post (Sflag);
cout << "Producing widget # " << produced << " in buffer # " << input <<
endl;
sem_post(Sfull);//increments full , tell consumer that it can consume now
usleep(rand () %997);
}
return &buf[0];
}
22
Named Semaphore example
void *Consumer(void *arg) {
int consumed= 0;
cout << "\nConsumer created.." << endl;
while(!terminatethreads) {
sem_wait(Sfull);
consumed = (consumed + 1) % BUFSIZE;
sem_wait(Sflag);
mycount--;
sem_post(Sflag);
cout << "Consuming widget # " << buf[consumed] << " in buffer # " <<
consumed << endl;
sem_post(Sempty);
usleep(rand () %1003);
}
return &buf[0];
}
static void sig_alarm(int signo) {
cout << "\nWe got the Signal Alarm, Terminating the threads...\n"<< endl;
terminatethreads=1;
return;
}
23
Mutexes in Pthreads (1)
Figure 2-30. Some of the Pthreads calls relating to mutexes.
cs431-cotter
Tanenbaum, Modern Operating Systems 3 e, (c) 2008 Prentice-Hall, Inc. All rights reserved. 0-13-6006639
24
Mutexes in Pthreads (2)
Figure 2-31. Some of the Pthreads calls relating
to condition variables.
cs431-cotter
Tanenbaum, Modern Operating Systems 3 e, (c) 2008 Prentice-Hall, Inc. All rights reserved. 0-13-6006639
25
Mutexes in Pthreads (3)
Figure 2-32. Using
threads to solve
the producerconsumer
problem.
cs431-cotter
Tanenbaum, Modern Operating Systems 3 e, (c) 2008 Prentice-Hall, Inc. All rights reserved. 0-13-6006639
26
Linux Interprocess
Communications
•
•
•
•
Unnamed Pipes
Named Pipes
Message Queues
Shared Memory
27
Unnamed pipes (pipes)
• Allow communications between related
processes.
• Unidirectional
• Used from command line to link commands
– ls -l | more
– cat -n myfile.cpp | lpr
• Used in programs to communicate between
processes
– pipetest.cpp
cs431-cotter
28
Pipe Commands
• popen
– FILE * popen (const char* cmd, const char *
type);
– type = “r”, “w”
• pclose
– int pclose (FILE * stream);
• #include <stdio.h>
cs431-cotter
29
Named Pipes
• Permanent objects
• Available to processes that can access the
filespace (same system or on a shared file
system)
• Processes do not have to be related.
cs431-cotter
30
Named Pipes (FIFO)
• int mkfifo(const char *name, mode_t mode);
– return is a file descriptor
– name is the name of the pipe
– mode is the permissions for the pipe (0666 = RDWR
all)
• int open(const char * name, int flags);
– flags = O_RDONLY, O_WRONLY, O_RDWR
• ssize_t read(int fd, void *buf, size_t count);
• ssize_t write(int fd, void *buf, size_t count);
cs431-cotter
31
Message Queues
• A “linked list of messages”
• Message queue has kernel persistence
– Supports asynchronous communications.
– Messages are stored in the queue, independent of
the sender (sender can close queue without losing
messages).
– Receiver can retrieve messages at a later time.
• Messages have a priority
– Higher priority messages are retrieved first (POSIX)
– Max priority is 32768
cs431-cotter
32
Message Queues
• Message Queue Capacity
–
–
–
–
(Can be set higher by root)
Max msgs: 10 /queue
Max Msg Size: 8192
Max # of Queues: 256
• Queues are created in their own virtual message
queue file system (mqueue)
– Can be mounted to view (and manipulate) queues
– mkdir /dev/mqueue
– mount –t mqueue none /dev/mqueue
cs431-cotter
33
Create and/or open a msg queue
• mqd_t mq_open (qName, flags, [mode], [attributes]);
– qName: Name of the queue to open / create
• Must be of the form “/qName”.
– flags: How queue will be opened/created.
• O_RDONLY | O_WRONLY | O_RDWR , [O_CREAT] )
– mode: File permissions for queue:
• S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP, S_IROTH, S_IWOTH
– attributes: Limits for the queue: struct mq_attr
•
•
•
•
long mq_flags: 0 | O_NONBLOCK (read queue non-blocking?)
long mq_maxmsg: max msgs in queue
long mq_msgsize: max msg size
long mq_curmsgs: How many messages are currently in queue?
cs431-cotter
34
Send a message to a queue
• mqd_t mq_send (queue_descr, msg, size, prior);
– Queue_descr: Like a file descriptor. Value returned
from mq_open.
– Msg: a pointer to a character buffer for the message
– Size: (size_t) size of message in bytes
– Prior: (unsigned int) priority of message
– Returns 0 on success, -1 on error
cs431-cotter
35
Receive a message from a
queue
• ssize_t mq_receive (queue_descr, msg, size, prior);
– Queue_descr: Like a file descriptor. Value returned from
mq_open.
– Msg: a pointer to a character buffer for the message
– Size: (size_t) size of buffer in bytes
– Prior: (*unsigned int) priority of message read.
– Returns number of bytes read (or -1 on error)
cs431-cotter
36
Get attributes of a Queue
• mqd_t mq_getattr (queue_descr, *struct
mq_attr);
– Queue_descr: Like a file descriptor. Value returned
from mq_open.
– *struct mq_attr: Pointer to struct that will return
attributes of the opened queue
• long mq_flags: 0 | O_NONBLOCK (read queue nonblocking?)
• long mq_maxmsg: max msgs in queue
• long mq_msgsize: max msg size
• long mq_curmsgs: How many messages are currently in
queue?
– Returns 0 on success, -1 on error
cs431-cotter
37
Removing (unlinking) a queue
• Mqd_t mq_unlink ( qName);
– qName: Name of queue
• Queue is removed from the message
queue file system. Any messages still in
the queue are lost.
• Returns 0 on success, -1 on error
cs431-cotter
38
mq_send
(Note: All error checking has been removed from the code
to focus on the details of message queue handling)
#include <mqueue.h> (also many other included header files…)
#define NAMESIZE 25
#define MSGCOUNT 5
#define MSGSIZE 512
using namespace std;
int main (int argc, char **argv) {
int lSize, bufSize, stat, i;
char qName[NAMESIZE];
char ans[5]; mqd_t mqd;
struct mq_attr qAtr;
unsigned int prio = 3;
char buf[MSGSIZE];
cs431-cotter
39
mq_send - 2
strncpy(qName, "/", 2);
strncat (qName, argv[1], lSize+1);
qAtr.mq_maxmsg = MSGCOUNT;
qAtr.mq_msgsize = MSGSIZE;
mqd = mq_open(qName, O_RDWR | O_CREAT, S_IRUSR |
S_IWUSR | S_IROTH | S_IWOTH, &qAtr);
do {
cout << "What message do you want to send? ";
cin.getline(buf, 80);
bufSize = strlen(buf);
cout << "What is the message priority? ";
cin >> prio;
stat = mq_send(mqd, buf, bufSize, prio);
cs431-cotter
40
mq_send - 3
if (stat == 0)
cout << "Send was successful" << endl;
else
exit(0);
cout << "Send another message (yes/no)?";
cin >> ans;
cin.ignore();
for (i = 0; i < 80; i++)
buf[i] = 0;
}while (ans[0] =='y');
mq_close(mqd);
return 0;
}
cs431-cotter
41
mq_recv - 1
Note: Most of the error checking code has been removed to focus on
the message queue portions of the code.
#include <mqueue.h> also many other #include files…
#define NAMESIZE 25
#define MSGCOUNT 25
#define MSGSIZE 512
#define BUFSIZE 9000
using namespace std;
int main (int argc, char **argv){
int lSize, bufSize, stat, msgcount, i, j;
char qName[NAMESIZE];
mqd_t mqd; struct mq_attr qAtr;
unsigned int prio = 3;
char buf[BUFSIZE];
cs431-cotter
42
mq_recv - 2
strncpy(qName, "/", 2);
strncat (qName, argv[1], lSize+1);
mqd = mq_open(qName, O_RDONLY);
mq_getattr(mqd, &qAtr);
msgcount = qAtr.mq_curmsgs;
cout << "There are currently " << msgcount << " messages in queue" << endl;
for (i= 0; i < msgcount; i++) {
stat = mq_receive(mqd, buf, BUFSIZE, &prio);
if (stat >= 0)
cout << "msg: " << buf << "; Prio: " << prio << endl;
else
cout << "Oops! Stat = " << stat << endl;
for (j = 0; j < 80; j++)
buf[j] = 0;
}//end of for loop
mq_close(mqd);
mq_unlink(qName); //delete the message queue
return 0;
}
cs431-cotter
43
Sample send Output
[rcotter@kc-sce-450p2 msgQ]$ ./mq_send nuQ
Message Queue name (/nuQ) is 4 characters
We opened the queue!
What message do you want to send? This is my first test message
What is the message priority? 2
Send was successful
Send another message (yes/no)?yes
What message do you want to send? This is my second test message
What is the message priority? 4
Send was successful
Send another message (yes/no)?yes
What message do you want to send? This is my third test message
What is the message priority? 1
Send was successful
Send another message (yes/no)?no
[rcotter@kc-sce-450p2 msgQ]$
cs431-cotter
44
Sample recv Output
[rcotter@kc-sce-450p2 msgQ]$ ./mq_recv nuQ
File name (/nuQ) is 4 characters
We opened the queue!
There are currently 3 messages in queue
msg: This is my second test message; Prio: 4
msg: This is my first test message; Prio: 2
msg: This is my third test message; Prio: 1
[rcotter@kc-sce-450p2 msgQ]$
cs431-cotter
45
Shared Memory
• Allows 2 or more processes to share the same
main memory space
– Memory can be allocated as blocks (pages) of
memory
– Memory can be mapped as a file that is available in
memory to multiple processes
cs431-cotter
46
Shared Memory
P1
P3
P2
cs431-cotter
47
Shared Memory
48
Shared Memory Usage
• Create a shared memory segment
• One or more processes attach to it
• Processes read and/or write to the segment.
Note that process sync is critical.
• All processes detach from shared memory
• One process removes (de-allocates) the
segment
cs431-cotter
49
Create a Shared Memory Segment
• Requires: <sys/ipc/h>, <sys/shm.h>
• int shmget (key_t, int size, int shmflg);
– Key_t:
• Shared memory segment number identifier (e.g. 15, 1000). Can be
used to create a new segment or ensure that an existing segment
still exists.
• IPC_PRIVATE- special variable that guarantees that a new
segment will be created
– Size:
• Size of the memory segment. Should be a multiple of th ememory
page size (typically 4096 in Linux).
– Shmflg:
• Flags that control behavior of the new segment.
• IPC_CREAT, IPC_EXCL, mode bits(9)
– Return (int)
• Shared memory ID – used to access or modify the shared memory
cs431-cotter
50
Shared Memory Segment Limits
ipcs -l
• Maximum segment size
– SHMMAX
32768 kbytes
• Minimum segment size
– SHMMIN
1 byte
• Total maximum # of segments
– SHMMNI
4096
• Total maximum shared memory
– SHMALL
8388608 kbytes
cs431-cotter
51
Control Shared Memory
• int shmctl (shmid, cmd, struct shmid_ds *buf);
– shmid: Shared memory identifier. (Value returned from
shmget())
– cmd:
• IPC_STAT – return status information about the shared memory in
buf.
• IPC_SET – modify the shared memory based on parameters in buf
(can only change UID and mode bits)
• IPC_RMID – Remove (deallocate) the shared memory segment
specified in shmid.
• IPC_LOCK – lock the shared memory segment in memory (don’t
swap out).
• IPC_UNLOCK –release the lock on shared memory
cs431-cotter
52
Attach to a Shared Memory
Segment
• void * shmat (shmid, shmaddr, shmflg);
– shmid: Shared memory identifier. (Value returned from shmget())
– shmaddr: Address where shared memory should attach to process.
• If 0, OS picks a suitable address
• If not 0 and SHM_RND flag is set, bind address will be given address,
rounded down to a page boundary
• If not 0 and SHM_RND is not set, address must be a page boundary
– shmflg:
• SHM_RND – round down the attach address to a page boundary
• SHM_RDONLY – open for read only. Process must have read access to the
segment
– Return value: Address at which the shared memory is mapped.
cs431-cotter
53
Detach from Shared Memory Segment
• int shmdt (shmaddr);
– shmaddr – address at which shared memory is
attached
– return 0 for success, -1 for fail
cs431-cotter
54
Shared Memory Example
#include <iostream>, etc…
#define SHM_SIZE
2048
#define ARRAYSIZE
50
#define LOOPCOUNT
1000000
#define PCOUNT
3
using namespace std;
int main( ) {
int shmid, i, j, k, sum, *shm, *myNum;
int pid, procNum, n1, n2;
int myNumbers[ARRAYSIZE];
int s[3]; //seeds for rand();
char sem1[] = “/semBlock”;
sem_t
*Scount;
for (i = 0; i < ARRAYSIZE; i++) //Fill array with 0-49. Sum = 1225
myNumbers[i] = i;
55
Shared Memory Example
if ((shmid=shmget(IPC_PRIVATE,SHM_SIZE,IPC_CREAT|0660))< 0)
perror("shmget fail");
return 1;
}
if ((shm = (int *)shmat(shmid, 0, 0)) == (int *) -1)
{
perror("shmat : parent");
return 2;
}
cout << "Shared memory is at: " << hex << shm << dec << endl;
myNum = shm;
// myNum now references shared mem
//Now we need to copy our array of numbers into shared memory
memcpy (myNum, &myNumbers, sizeof(myNumbers));
sum = 0;
for (i = 0; i < ARRAYSIZE; i++) {
cout << myNum[i] << " , ";
sum += myNum[i];
}
cout << "\nThe sum of all values is " << sum << endl;
cout << "In parent before fork, memory is: " << shm << endl;
Scount = sem_open(sem1, O_CREAT, 0666, 1);
sem_close (Scount);
{
56
Shared Memory Example
for (i = 0; i < PCOUNT; i++) {
if ((pid = fork()) < 0) //fork failed {
cout << "Fork failed!!" << endl;
return 2;
}
else if (pid == 0) //We're in the child
{
srand(s[i]); // seed the random number generator
procNum = i;
Scount = sem_open(sem1, 0);
cout << "In child " << procNum << " memory is: " << shm << endl;
for (j = 0; j < LOOPCOUNT; j++)
{
n1 = (rand() % 50);
n2 = (rand() %50);
sem_wait (Scount);
myNum[n1]+= 1;
myNum[n2] -= 1;
sem_post (Scount);
}//end of for ...
sem_close(Scount);
return 0; //child is done.
} //end of if pid == 0
else //We're in the parent {
cout << "We just created child " << i << " with pid " << pid << endl;
}//end of for ---PCOUNT
57
Shared Memory Example
//The parent now needs to wait for the children (at least 1) to finish
wait(0);
cout << "In parent after fork, memory is : " << shm << endl;
sum = 0;
for (i = 0; i < ARRAYSIZE; i++) {
cout << myNum[i] << " , ";
sum += myNum[i];
}
cout << "\nThe sum of the array is now " << sum << endl;
cout << "\nParent removing shared memory" << endl;
sem_unlink(sem1);
shmdt(shm);
shmctl (shmid, IPC_RMID, (struct shmid_ds *) 0);
return 0;
}
58
rcotter@kc-sce-450p2 shmem]$ ./sharedmem_s
Shared memory is at: 0xb78ed000
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 ,
22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 ,
42 , 43 , 44 , 45 , 46 , 47 , 48 , 49 ,
The sum of all values is 1225
In parent before fork, memory is: 0xb78ed000
We just created child 0 with pid 18745
In child 0 memory is: 0xb78ed000
We just created child 1 with pid 18746
The sum for child 0 is 1225
In child 2 memory is: 0xb78ed000
The sum for child 2 is 1225
We just created child 2 with pid 18747
In child 1 memory is: 0xb78ed000
The sum for child 1 is 1225
:
The sum for child 2 is 1225
Child 0 just did 1000000 loops
Child 18745 just terminated
The sum for child 1 is 1225
:
Child 1 just did 1000000 loops
Child 18746 just terminated
The sum for child 2 is 1225
:
Child 2 just did 1000000 loops
Child 18747 just terminated
In parent after fork, memory is : 0xb78ed000
167 , 425 , 83 , 320 , 162 , -387 , -120 , -236 , 712 , 548 , 136 , -391 , -82 , 561 , -362 ,
-115 , 555 , 7 , -169 , -492 , -459 , 113 , -58 , 19 , 130 , -581 , 266 , 36 , 524 , -272 ,
-393 , -119 , -65 , 24 , 495 , 367 , -315 , -225 , -146 , 515 , -173 , 321 , -91 , -60 , 69 ,
-111 , 6 , 468 , -56 , -326 ,
The sum of the array is now 1225
Shared Memory
Example – W/ Sync
Parent removing shared memory
[rcotter@kc-sce-450p2 shmem]$
59
[rcotter@kc-sce-450p2 shmem]$ ./sharedmem
Shared memory is at: 0xb77cb000
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 ,
22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 ,
42 , 43 , 44 , 45 , 46 , 47 , 48 , 49 ,
The sum of all values is 1225
In parent before fork, memory is: 0xb77cb000
We just created child 0 with pid 18681
We just created child 1 with pid 18682
We just created child 2 with pid 18683
In child 2 memory is: 0xb77cb000
The sum for child 2 is 1225
In child 0 memory is: 0xb77cb000
The sum for child 0 is 1226
In child 1 memory is: 0xb77cb000
The sum for child 1 is 1222
The sum for child 0 is 1221
:
Child 18681 just terminated.
The sum for child 2 is 343
The sum for child 1 is 343
:
Child 18683 just terminated.
The sum for child 1 is 290
:
Child 18682 just terminated.
In parent after fork, memory is : 0xb77cb000
-204 , -443 , -85 , -339 , -178 , 390 , 101 , 232 , -717 , -548 , -116 , 384 , 102 , -533 , 365 ,
123 , -537 , 52 , 217 , 497 , 485 , -101 , 100 , -4 , -99 , 619 , -216 , 6 , -500 , 316 , 432 ,
152 , 98 , 29 , -433 , -333 , 368 , 289 , 187 , -461 , 232 , -257 , 152 , 130 , 4 , 175 , 30 ,
-386 , 121 , 392 ,
The sum of the array is now 290
Each process ran through 1000000 iterations
Parent removing shared memory
[rcotter@kc-sce-450p2 shmem]$
Shared Memory
Example –
W/O Sync
60
Summary
• Several different sync mechanisms available in
Linux
–
–
–
–
Signal
Wait
Mutex
Semaphore
• Several different IPC mechanisms
– Pipes
– Message queues
– Shared Memory
• Linux specifications consistent with POSIX
cs431-cotter
cs431-cotter
61
Questions
• What is a signal handler table? Where is it located? How is it used
by a process to handle signals sent to the process?
• How do you set up a program (process) to provide customized
handling of a signal? (What code is needed to replace the default
signal handler with our own signal handling routine?
• What function would a parent process use to capture the exit code
of a terminated child process? If the parent process creates multiple
child processes, how could it wait for one specific child process to
terminate?
• If two processes want to pass information using an named pipe,
what must the relationship be between those processes (no relation
required, parent and child, children of the same parent, processes in
the same system, etc.)
• What functions (system calls) would be needed to create and
initialize a semaphore in Linux? What functions are needed to
actually use the semaphore in your program?
cs431-cotter
cs431-cotter
62