interprocess communication in unix paulo marques department of informatics engineering university of...
Post on 19-Dec-2015
221 views
TRANSCRIPT
![Page 1: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/1.jpg)
InterprocessCommunication in Unix
Paulo MarquesDepartment of Informatics EngineeringUniversity of [email protected]
2006
/200
7
An Introduction toConcurrent Programming
![Page 2: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/2.jpg)
2
Contents
Concurrent Programming Concepts Process Creation and Management Signals Pipes, Named Pipes and Unix Sockets IO Multiplexing Message Queues Shared Memory Semaphores POSIX Threads
Creation and Management Synchronization
![Page 3: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/3.jpg)
3
Standards
There are many UNIX flavors around... Linux, HP-UX, Solaris, AIX, BSD, IRIX, etc. Different capabilities, different APIs for advanced
functionalities
Vendors tried to find a common ground: POSIX = Portable Operating System Interface
Standards? UNIX System V (Release 4) BSD 4.3 (1988) POSIX.1 (1994) POSIX Spec. 1170 (2001) IEEE Std. 1003.1-2001 (or POSIX)
![Page 4: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/4.jpg)
4
POSIX Extensions
There is the 2001 base standard and there’s its extensions Implementations that comply with the base standard
define _POSIX_VERSION to 200112L in <unistd.h>
![Page 5: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/5.jpg)
5
POSIX Extensions (2)
And many, many more...
![Page 6: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/6.jpg)
6
Man pages typically indicate compliance
![Page 7: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/7.jpg)
InterprocessCommunication in Unix
Paulo MarquesDepartment of Informatics EngineeringUniversity of [email protected]
2006
/200
7
Process Creation and Management
![Page 8: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/8.jpg)
8
Process Model
Process creation in Unix is based on spawning child processes which inherit all the characteristics of their fathers Variables, program counter,
open files, etc. Spawning a process is done
using the fork() system call
After forking, each process will be executing having different variables and different state. The Program Counter will be
pointing to the next instruction
Changing a variable in the child program doesn’t affect its father (and vice-versa)
a = f();fork();b = g();
State
a = f();fork();b = g();
State
a = f();fork();b = g();
State
Child Process
Original Process
Original Process
![Page 9: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/9.jpg)
9
Process Management
Each process has an unique identifier (PID). Each process has a father, which is also identified (PPID).
pid_t getpid(void);Returns the PID of the current process.
pid_t getppid(void);Returns the PID of the parent process.
pid_t fork(void);Creates a new process which inherits all its father’s state. It returns 0 on the original process and the child’s PID in the spawned process.
pid_t wait(int* status);Waits until a child process exits. The status of the child is set in status. (status is the return value of the process)
pid_t waitpid(pid_t who, int* status, int options);Same as wait() but allows to wait for a particular child. In options, by using WNOHANG in options, allows for checking if a child has already exited without blocking. 0 in who means “wait for any child”.
![Page 10: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/10.jpg)
10
Using processes for doing different things
The key idea is to create asymmetry between processes
#include <stdio.h>#include <unistd.h>#include <sys/wait.h>#include <sys/types.h>
int main(){ pid_t id;
id = fork(); if (id == 0) { printf("[%d] I'm the son!\n", getpid()); printf("[%d] My parent is: %d\n", getpid(), getppid()); } else { printf("[%d] I'm the father!\n", getpid()); wait(NULL); } return 0;}
![Page 11: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/11.jpg)
11
And the result is...
But why did we do wait(NULL)?
...printf("[%d] I'm the father!\n", getpid());wait(NULL);...
![Page 12: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/12.jpg)
12
Process Termination in UNIX
A process is only truly eliminated by the operating system when it’s father calls wait()/waitpid() on it. This allows the parent check things like the exit code of its
son’s
Zombie Process: One that has died and it’s parent has not acknowledged its death (by calling wait()) Be careful with this if your are designing servers. They are
eating up resources!!
Orphan Process: One whose original parent has died. In that case, it’s parent becomes init (process 1).
![Page 13: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/13.jpg)
13
Let’s generate some Zombies
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/wait.h>#include <sys/types.h>
void worker() { printf("[%d] Hi, I'm a worker process! Going to die...\n", getpid());}
int main() { for (int i=0; i<10; i++) { if (fork() == 0) { worker(); exit(0); } } printf("[%d] Big father is sleeping!\n", getpid()); sleep(10);
return 0;}
![Page 14: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/14.jpg)
14
Zombies (2)
![Page 15: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/15.jpg)
15
Let’s see adoption by init
#include (...)
void worker(){ sleep(10); printf("[%d] Let's see who my dady is: %d\n", getpid(), getppid());}
int main(){ for (int i=0; i<10; i++) { if (fork() == 0) {
worker();exit(0);
} }
printf("[%d] Big dady is going away!\n", getpid()); return 0;}
![Page 16: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/16.jpg)
16
And the result is...
![Page 17: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/17.jpg)
17
How to structure code
(...)
if ((id = fork()) == 0){ // Huge amount of code // ...}else{ // Huge amount of code // ...}
(...)
Fairly common...Don’t do it!
![Page 18: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/18.jpg)
18
How to structure code
void client(int id){ // Client code // ...}
if ((id = fork()) == 0){ client(id); exit(0);}else if (id == -1){ error();}
// Original process code// ...
Server
Client Client Client
Note: You still have to consider how to take care of zombies
![Page 19: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/19.jpg)
19
How a process becomes another executable
Somehow the OS must be able to execute code starting from an executable file e.g. how does the shell (bash) becomes ‘ls’?
int execl(const char *path, const char *arg, ...);int execlp(const char *file, const char *arg, ...);int execle(const char *path, const char *arg, ..., char *const envp[]);int execv(const char *path, char *const argv[]);int execvp(const char *file, char *const argv[]);
“exec family” of functions Allow to substitute the current process executable image by
another one. The substitution is complete! The functions that have a ‘p’ make use of the environment
PATH; The functions that have a ‘v’ make use of a pointer to an array on parameters; The functions that have an ‘l’ have the parameters passed separated by commas
Make sure that the first parameter is the name of the program!
![Page 20: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/20.jpg)
20
Example
Simple program that lists the files in the current directory
Note: A successful exec() never returns The code, the stack, the heap, it’s all replaced by the new
executable
Original Code “ls code”
“ls code”
exec()
![Page 21: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/21.jpg)
21
The corresponding code...
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>
int main(){ if (execlp("ls", "ls", "-a", NULL) == -1) perror("Error executing ls: "); else printf("This cannot happen!\n");
return 0;}
char* ls_param[] = { "ls", "-a", NULL };
if (execvp(ls_param[0], ls_param) == -1) perror("Error executing ls: ");
Using an arraycan be more flexible...
![Page 22: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/22.jpg)
InterprocessCommunication in Unix
Paulo MarquesDepartment of Informatics EngineeringUniversity of [email protected]
2006
/200
7
Asynchronous Events:Signals
![Page 23: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/23.jpg)
23
Signals
A signal represents an asynchronous event which an application must (should? can?) process The programmer can register a routine to handle such
events Examples:
The user hits Ctrl+C SIGINT The system requests the application to terminate
SIGTERM The program tried to write to a closed channel
SIGPIPEProcess
normal flowof execution
int sigint_handler() { // process signal}
SIGINT
![Page 24: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/24.jpg)
24
Signals (2)
Signals can be in one of four states: Blocked:
Upon arrival, they are stored in a queue until the process unblocks them. Then, they are delivered.
Ignored:Upon arrival, they are discarded. It is as if they had never existed.
Being Handled:They are redirected to a signal handler which is called.
None of the above:Non-handled, non-blocked or ignored signals. Upon arrival, they cause program termination.
Some signals cannot be ignored or handled (e.g. SIGKILL)
When a process starts, signals are on their “default behavior”. Some are ignored, most are in the “non-handled, non-blocked
nor ignored state”. If a signal occurs, the process will die.
![Page 25: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/25.jpg)
25
Basic Signal Routines
typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);
Redirects a certain signal (signum) to a handler routine.
int kill(pid_t pid, int sig); Sends a signal to a certain process identified by a PID. (Note: if pid is 0, sends to all processes in the current process group.)
int pause();Blocks the process until a signal is received.
prototype of the handler routine
int sigaction(); int sigprocmask(); int sigpending(); int sigsuspend();
Note: These are the recommended POSIX routines. We are not going to cover them here. The problem with signal() is that in certain cases its behavior is undefined across systems.
![Page 26: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/26.jpg)
26
Handling a signal
void sigint(int signum) { char option[2]; printf("\n ^C pressed. Do you want to abort? ");
scanf("%1s", option); if (option[0] == 'y') { printf("Ok, bye bye!\n"); exit(0); }}
int main(){ // Redirects SIGINT to sigint() signal(SIGINT, sigint);
// Do some work! while (1) { printf("Doing some work...\n"); sleep(1); } return 0;}
![Page 27: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/27.jpg)
27
Handling a signal (2)
![Page 28: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/28.jpg)
28
Special constants in signal()
signal(SIGINT, SIG_IGN)Ignores SIGINT
signal(SIGINT, SIG_DFL)Restores SIGINT to its
“default” handling
![Page 29: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/29.jpg)
29
The problem with signals
They make programming extremely hard It’s completely asynchronous: you never know when you
are going to get a signal This means that you have to protect all calls!
After calling a standard function, it may return -1 indicating an error errno==EINTR means that a certain routine was
interrupted and has to be tried again. Other routines return other things. It you are using signals, you have to protect them against
all that!
![Page 30: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/30.jpg)
30
The problem with signals (2)
For instance, simply to try to read a “struct person” from disk...
struct person p;...int n, total = 0;while (total < sizeof(p)) { n = read(fd, (char*)p + total, sizeof(p)-total); if (n == -1) { if (errno == EAGAIN) continue; else { // True error! } } total+= n;}
And you have to do something like this for all calls being done in your program!
![Page 31: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/31.jpg)
31
Sending a signal
It’s just a question of calling kill() with the PID of the target process...
void master(pid_t pid_son){ printf("Master sleeping for a while...\n"); sleep(3); printf("Master says: Hello son!\n"); kill(pid_son, SIGUSR1);}
int main() { pid_t son;
// Creates a worker process if ((son=fork()) == 0) { worker(); exit(0); } // The master master(son); wait(NULL); return 0;}
![Page 32: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/32.jpg)
32
The code of the child process...
void dady_call(int signum) { printf("Dady has just called in!\n");}
void worker() { // Redirect "user signal 1" to a handler routine signal(SIGUSR1, dady_call);
// Do some work printf("Child process, life is good...\n"); for (int i=0; i<10; i++) { printf("Child doing some work\n"); sleep(1); } printf("Child saying bye bye!\n");}
![Page 33: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/33.jpg)
33
And the result is...
![Page 34: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/34.jpg)
34
Danger!!!
What do you think it will happen if you receive a signal inside a signal handler?? In most systems, upon entering a signal handling routine, all
signals of that type become blocked (i.e. they are queued). [Well, for “normal” signals, a finite set of them are queued (typically 1); for “real time signals”, all are...]
The other signals are still processed asynchronously if they arrive.
This behavior is not consistent across systems. In fact, in some systems, that signal type resets to its default behavior. This means that if, meanwhile, the program receives a signal of the same type it may die! On that type of system, the first thing that you must do is to once again set the signal handler.
Well... doesn’t really solve the problem, it just makes it less likely.
The new POSIX routines address this – use them. Also, most system nowadays don’t reset the signal handler.
void dady_call(int signum) { signal(SIGUSR1, dady_call); printf("Dady has just called in!\n");}
![Page 35: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/35.jpg)
35
Beware
Signal numbers vary across operating systems and architectures. Don’t rely on them, use symbolic constants
Linux, i386
“man 7 signal”
![Page 36: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/36.jpg)
36
Some Signals
![Page 37: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/37.jpg)
InterprocessCommunication in Unix
Paulo MarquesDepartment of Informatics EngineeringUniversity of [email protected]
2006
/200
7
Pipes, Named Pipes andUNIX Sockets
![Page 38: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/38.jpg)
38
Stream mode of communication
Pipes, Named Pipes and Stream Unix SOCKETS allow processes to communicate using “streams of data” A “pipe” is a connection between two processes. You can
send things through the pipe, you can try to receive things from the pipe.
A pipe acts like a synchronous finite buffer. If a process tries to write to a pipe that is full, it blocks If a process tries to read from a pipe that is empty, it blocks
write() read()
pipe
![Page 39: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/39.jpg)
39
Pipes
Provides for communication amount processes that are hierarchically related (i.e. father-child) Pipes must be created prior to creating child processes
Whenever a pipe is created, using pipe(), two file descriptors are opened: one for reading (fd[0]), one for writing (fd[1]) Unused file descriptors should be closed!
Pipes are unidirectional (well... normally)
fd[1] fd[0]int fd[2];
pipe(fd);readingwriting
![Page 40: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/40.jpg)
40
Example
typedef struct { int a; int b;} numbers;
// File descriptors for the pipe channelint channel[2];(...)
int main() { // Create a pipe pipe(channel);
// Create the processes if (fork() == 0) { worker(); exit(0); } master(); wait(NULL); return 0;}
![Page 41: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/41.jpg)
41
Example (cont.)
void worker() { numbers n;
close(channel[1]);
while (1) { read(channel[0], &n, sizeof(numbers)); printf("[WORKER] Received (%d,%d) from master to add. Result=%d\n", n.a, n.b, n.a+n.b); }}
void master(){ numbers n; close(channel[0]); while (1) { n.a = rand() % 100; n.b = rand() % 100; printf("[MASTER] Sending (%d,%d) for WORKER to add\n", n.a, n.b); write(channel[1], &n, sizeof(numbers)); sleep(2); }}
![Page 42: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/42.jpg)
42
The result is...
![Page 43: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/43.jpg)
43
Be careful!
A pipe is a finite buffer. If you try to write too much too quickly into it, the process will block until some space clears up.
Atomicity is something to be dealt with If you try to write less that PIPE_BUF bytes into a pipe, you are
guarantied that it will be written atomically It you try to write more, you have no guaranties! If several processes
are writing at the same time, the writes can be interleaved Also, when a process tries to read from a pipe, you are not guarantied
that it will be able to read everything Meaning...
You must synchronize your writes when you’re writing a lot of data! You must ensure that you read complete messages!
struct person p;
int n, total = 0;while (total < sizeof(p)) { n = read(fd[0], (char*)p + total, sizeof(p)-total); total+= n;}
![Page 44: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/44.jpg)
44
Controlling File Descriptors
Each process has a file descriptor table. By default, entries 0, 1 and 2 are: stdin, stdout, stderr.
Each time a file is open, an entry is added to this table. Each time a file is closed, the corresponding entry becomes available.
The process descriptor table, in fact, contains only references to the OS global file descriptor table.
<free>
<free>
0
1
2
3
4
5
6
stdin
stdout
stderr
f2
f3 File Descriptor Table after:open(“f1”)open(“f2”)open(“f3”)close(“f1”)
![Page 45: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/45.jpg)
45
Controlling File Descriptors (2)
Two routines are useful for controlling file descriptors: int dup(int fd)
Duplicates file descriptor “fd” on the first available position of the file descriptor table.
int dup2(int fd, int newfd)Duplicates file descriptor “fd” on the “newfd” position, closing it if necessary.
Note that after a file descriptor is duplicated, the original and the duplicate can be used interchangeably. They share the file pointers, the buffers, locks, etc. Careful: Closing one file descriptor doesn’t close all other
that have been duplicated!
![Page 46: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/46.jpg)
46
Implementing a pipe between two processes
Implementing a pipe between two processes is quite easy. It’s only necessary to associate the standard output of one process with the standard input of another.
Simple example: “ls | sort”.
Note: closing one file descriptor doesn’t close all other that have been duplicated!
![Page 47: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/47.jpg)
47
Resulting in...
![Page 48: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/48.jpg)
48
Named Pipes (also known as FIFOs)
Similar to pipes but allow communication between unrelated processes. Each pipe has a name (string). The pipe is written persistently in the file system. For creating a named pipe, use the “mkfifo” command or
call mkfifo(const char* filename, mode_t mode);
Typically, like pipes, they are half-duplex Means that the must be open read-only or write-only They are opened like files, but they are not files You cannot fseek() a named pipe; write() always appends
to the pipe, read() always returns data from the beginning of the pipe.
After data is read from the named pipe, it’s no longer there. It’s not a file, it’s an object in the unix kernel!
![Page 49: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/49.jpg)
49
Unrelated client/server program (np_server.c)
#define PIPE_NAME "np_client_server"(...)
int main(){ // Creates the named pipe if it doesn't exist yet if ((mkfifo(PIPE_NAME, O_CREAT|O_EXCL|0600)<0) && (errno!= EEXIST)) { perror("Cannot create pipe: "); exit(0); }
// Opens the pipe for reading int fd; if ((fd = open(PIPE_NAME, O_RDONLY)) < 0) { perror("Cannot open pipe for reading: "); exit(0); }
// Do some work numbers n; while (1) { read(fd, &n, sizeof(numbers)); printf("[SERVER] Received (%d,%d), adding it: %d\n", n.a, n.b, n.a+n.b); } return 0;}
![Page 50: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/50.jpg)
50
Unrelated client/server program (np_client.c)
#define PIPE_NAME "np_client_server"(...)
int main(){ // Opens the pipe for writing int fd; if ((fd = open(PIPE_NAME, O_WRONLY)) < 0) { perror("Cannot open pipe for writing: "); exit(0); }
// Do some work while (1) { numbers n; n.a = rand() % 100; n.b = rand() % 100; printf("[CLIENT] Sending (%d,%d) for adding\n", n.a, n.b); write(fd, &n, sizeof(numbers)); sleep(2); }
return 0;}
![Page 51: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/51.jpg)
51
Executing them...
![Page 52: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/52.jpg)
52
Some interesting issues...
If you get a SIGPIPE signal, this means that you are trying to read/write from a closed pipe
A named pipe is a connection between two processes. A process blocks until the other party open the pipe... Being it for reading or writing. It’s possible to bypass this behavior (open it non-blocking –
O_NONBLOCK), but be very, very careful: if not properly programmed, it can lead to busy waiting. If a named pipe is open non-blocking, EOF is indicated when read() returns 0.
When designing a client/server multiple client application, this means that either the pipe is re-opened after each client disconnects, or the pipe is open read-write.
If opened “read-write”, the server will not block until the other party connects (since, he itself is also another party!)
![Page 53: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/53.jpg)
53
Unix Domain Sockets [Very Briefly!]
Similar to Internet sockets but on the local machine Both connection-oriented and datagram Datagram sockets are reliable (not lost nor delivered out-
of-order)
It’s a little bit of a mix between sockets and pipes It’s possible to use a “network-oriented socket interface”
to use them It’s easy to create a pair of unnamed, connected domain
sockets between two processes
They are much lighter than TCP/IP Sockets No protocol processing, no network headers, no
checksums, no sequence numbers... just plain memcpy-ing.
![Page 54: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/54.jpg)
54
Simple (non-concurrent) Echo Server
#define SOCK_NAME "/tmp/my_echo"#define OK_MESSAGE "Ok, got it!"#define BUF_SIZE 4096#define BACKLOG 5
// Our server socket descriptorint sock;
void create_socket() { // Creates the unix socket and binds it assert( (sock = socket(AF_UNIX, SOCK_STREAM, 0)) != -1 ); struct sockaddr_un local; local.sun_family = AF_UNIX; strcpy(local.sun_path, SOCK_NAME); unlink(local.sun_path); int len = strlen(local.sun_path) + sizeof(local.sun_family); assert( bind(sock, (struct sockaddr *) &local, len) != -1 ); assert( listen(sock, BACKLOG) != -1);}
int main() { create_socket(); process_clients(); return 0;}
![Page 55: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/55.jpg)
55
Simple (non-concurrent) Echo Server (2)
void process_clients(){ struct sockaddr_un remote; int connection; socklen_t addr_len; while (1) { printf("Waiting for a connection...\n"); addr_len = sizeof(remote); assert( (connection = accept(sock, (struct sockaddr *) &remote, &addr_len)) != -1); printf("Connected.\n");
// Receive and send a message (highly simplified) char buf[BUF_SIZE]; int n = read(connection, buf, BUF_SIZE); buf[n] = '\0'; printf("Read from socket: %s\n", buf); write(connection, OK_MESSAGE, strlen(OK_MESSAGE)+1); close(connection); }}
![Page 56: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/56.jpg)
56
Simple (non-concurrent) Echo Client
(...)
#define SOCK_NAME "/tmp/my_echo"#define BUF_SIZE 4096
// Our socket descriptorint sock;
void connect_socket() { struct sockaddr_un remote; socklen_t addr_len; assert( (sock = socket(AF_UNIX, SOCK_STREAM, 0)) != -1); printf("Trying to connect...\n");
remote.sun_family = AF_UNIX; strcpy(remote.sun_path, SOCK_NAME); addr_len = strlen(remote.sun_path) + sizeof(remote.sun_family); if (connect(sock, (struct sockaddr *) &remote, addr_len) == -1) { perror("Could not connect: "); exit(1); }
printf("Connected.\n");}
![Page 57: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/57.jpg)
57
Simple (non-concurrent) Echo Client (2)
void send_message(const char* msg){ write(sock, msg, strlen(msg)+1); char buf[BUF_SIZE]; int n = read(sock, buf, BUF_SIZE); buf[n] = '\0'; printf("Read from server: %s\n", buf); close(sock);}
int main(int argc, char* argv[]){ char* msg = "Hello server!"; if (argc == 2) msg = argv[1];
connect_socket(); send_message(msg);}
![Page 58: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/58.jpg)
58
The result is:
![Page 59: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/59.jpg)
59
Checking active Unix sockets
“netstat -a”
![Page 60: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/60.jpg)
InterprocessCommunication in Unix
Paulo MarquesDepartment of Informatics EngineeringUniversity of [email protected]
2006
/200
7
I/O Multiplexing
![Page 61: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/61.jpg)
61
Interesting Problem
A printer daemon is connected to a physical printer There are 3 named-pipes which allow automatic
formatted printing
PrinterDaemon
/printer/a4_double_sided
/printer/a4_single_sided
/printer/a3_single_sided
Pipes are blocking, so this doesn’t work!!!
![Page 62: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/62.jpg)
62
I/O Multiplexing
I/O Multiplexing: The ability to examine several file descriptors at the same time select() and pselect()
int select(int n, fd_set* readfd, fd_set* writefd, fd_set* exceptfd, struct timeval* timeout)
Blocks until activity is detected or a timeout occurs.
Greatest fd plus oneFor reading activityFor writing activityFor out-of-band activity
The fd_set variables are input/output. Upon return, they indicateif there was activity in a certain descriptor or not.
![Page 63: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/63.jpg)
63
select()
Careful: n is the number of the highest filedescriptor added of one. It’s not the number of file descriptors
fd_setA bit set representing file descriptors
FD_ZERO(fd_set* set)Cleans up the file descriptor set
FD_SET(int fd, fd_set* set)Sets a bit in the file descriptor set
FD_CLEAR(int fd, fd_set* set)Clears a bit in the file descriptor set
FD_ISSET(int fd, fd_set* set)Tests if a file descriptor is set
![Page 64: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/64.jpg)
64
Example (printerd.c)
(...)
#define BUF_SIZE 4096#define NUM_PRINTERS 3
const char* PRINTER_NAME[] = { "printer1", "printer2", "printer3" };
// The printer file descriptorsint printer[NUM_PRINTERS];
void create_printers() { for (int i=0; i<NUM_PRINTERS; i++) { unlink(PRINTER_NAME[i]); mkfifo(PRINTER_NAME[i], O_CREAT|O_EXCL|0666); printer[i] = open(PRINTER_NAME[i], O_RDONLY|O_NONBLOCK); assert(printer[i] >= 0); }}
int main(int argc, char* argv[]) { create_printers(); accept_requests();}
![Page 65: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/65.jpg)
65
Example (printerd.c) (2)
void accept_requests() { while (1) { fd_set read_set; FD_ZERO(&read_set); for (int i=0; i<NUM_PRINTERS; i++) FD_SET(printer[i], &read_set);
if ( select(printer[NUM_PRINTERS-1]+1, &read_set, NULL, NULL, NULL) > 0 ) { for (int i=0; i<NUM_PRINTERS; i++) { if (FD_ISSET(printer[i], &read_set)) { printf("[<%s> PRINTING]: ", PRINTER_NAME[i]);
char buf[BUF_SIZE]; int n = 0; do { n = read(printer[i], buf, BUF_SIZE); if (n > 0) { buf[n] = '\0'; printf("%s", buf); } } while (n > 0);
close(printer[i]); printer[i] = open(PRINTER_NAME[i], O_RDONLY|O_NONBLOCK); } } } } }
![Page 66: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/66.jpg)
66
Resulting in...
![Page 67: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/67.jpg)
InterprocessCommunication in Unix
Paulo MarquesDepartment of Informatics EngineeringUniversity of [email protected]
2006
/200
7
Message Queues
![Page 68: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/68.jpg)
68
Types of communication
Streams represent “a flow” of bytes. There are no fixed data boundaries. The sender requests the transmission of N bytes The data starts flowing, the receiver starts getting it The receiver may get several chucks of less then N bytes
Messages represent a complete fixed structure of data It’s like sending a letter. Either you get if fully or you
don’t. You don’t get “half a letter”.
169
![Page 69: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/69.jpg)
69
Message Queues
Another IPC mechanism Based on messages, not no data streams
Completely asynchronous A process can start executing, write some messages to a
message queue and die; another process can latter on come alive an receive them.
Sharp contrast with all the mechanisms that we’ve seen so far, which require both the sender and the receiver to be present at the same time
Message queues are maintained by the operating system. They are not destroyed if a process dies!
msgsnd() msgrcv()
![Page 70: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/70.jpg)
70
Message Queues – System V
int msgget(key_t key, int flags)Obtains an identifier to an existing message queue or creates a new one. “key” can be IPC_PRIVATE (which creates a new unique
identifier), or an existing identifier. ftok() can be used to generate a number based on a filename.
“flags”, normal mode flags. When ORed with IPC_CREAT creates a new one.
int msgctl(int mqid, int cmd, struct msqid_ds* buff)Provides a variety of control operations on the message queue. “mqid” is the value returned by msgget() “cmd” is the command (most usually: IPC_RMID to remove it) “buff” a structure used in some control operations
![Page 71: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/71.jpg)
71
Message Queues – System V (2)
int msgsnd(int mqid, const void* message, size_t length, int flags)Sends a message to a certain key. “mqid” is the value returned by msgget() “message” it’s a pointer to the message to send “length” represents the length of the payload of the message
(not total) “flags”: 0 or IPC_NOWAIT (non-blocking)
int msgrcv(int mqid, void* message, size_t length, int type, int flags)Retrieves a message from a message queue. “mqid” is the value returned by msgget() “message” it’s a pointer to the message to receive “length” represents the maximum payload we are willing to
receive “type” represent the type of message to receive (0 FIFO) “flags”: 0 or IPC_NOWAIT
![Page 72: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/72.jpg)
72
Messages a Message Payload
In System V a message can be anything. But, it must always have a “long” integer in the beginning This long is called a message type identifier
typedef struct{ long mtype; int first; int second;} numbers_message;
Message type (must be >0)!
Payload
![Page 73: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/73.jpg)
73
mq_pong.c (1)
typedef struct { long mtype; int first, second;} numbers_msg;
// Message queue idint id;
void cleanup(int signum) { msgctl(id, IPC_RMID, NULL); exit(0);}
void main(int argc, char* argv[]) { assert( (id = msgget(IPC_PRIVATE, IPC_CREAT|0700)) != 0 ); signal(SIGINT, cleanup); if (fork() == 0) ping(); else pong();}
![Page 74: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/74.jpg)
74
mq_pong.c (2)
void ping(){ numbers_msg msg; msg.first = rand() % 100; msg.second = rand() % 100; while (1) { msg.mtype = 1; printf("[A] Sending (%d,%d)\n", msg.first, msg.second); msgsnd(id, &msg, sizeof(msg)-sizeof(long), 0); msgrcv(id, &msg, sizeof(msg)-sizeof(long), 2, 0); printf("[A] Received (%d,%d)\n", msg.first, msg.second); ++msg.first; ++msg.second; sleep(3); }}
![Page 75: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/75.jpg)
75
mq_pong.c (3)
void pong(){ numbers_msg msg;
while (1) { msgrcv(id, &msg, sizeof(msg)-sizeof(long), 1, 0); printf("[B] Received (%d,%d)\n", msg.first, msg.second);
msg.mtype = 2; ++msg.first; ++msg.second;
printf("[B] Sending (%d,%d)\n", msg.first, msg.second); msgsnd(id, &msg, sizeof(msg)-sizeof(long), 0); }}
![Page 76: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/76.jpg)
76
Resulting in...
![Page 77: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/77.jpg)
77
IPC Resources
Remember, IPC resources are not automatically cleaned
This can lead so serious resource leaks “ipcs” allows you to see the current System V IPCs in use “ipcrm” allows you to manually delete resources
![Page 78: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/78.jpg)
78
POSIX Message Queues
Very similar to System V except: Message types represent priorities A read from a POSIX message queue always returns the
oldest message of the largest type (priority) POSIX message queues allow a signal to be raised when a
message is put on an empty queue or the initiation of a thread
Messages queues are represented by names on the file system (like named pipes)
mq_open() mq_close() mq_unlink() mq_send() mq_receive()
![Page 79: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/79.jpg)
InterprocessCommunication in Unix
Paulo MarquesDepartment of Informatics EngineeringUniversity of [email protected]
2006
/200
7
Shared Memory and Semaphores
![Page 80: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/80.jpg)
80
Why shared memory?
Up until now... System calls are slow! Copying thought the kernel is slow!
P1 P2
buffer
write() read()
User Space
Kernel Space
![Page 81: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/81.jpg)
81
Why shared memory?
Shared Memory (Almost) No kernel involvement! Fast! Very Fast!
P1 P2
sharedbuffer
User Space
Kernel Space
Dangerous, very dangerous!
![Page 82: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/82.jpg)
82
How does it work
Each process has an address space Each address space corresponds to a page table. There
are as many page tables as there are processes Shared memory corresponds to putting the same
“real memory pages” in the page tables of two different processes
0 0
4Gb 4Gb
Address SpaceProcess A
Address SpaceProcess B
1000 1000
Physical Memory0
256Mb5000
Page Translation
(slightly simplified)
![Page 83: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/83.jpg)
83
Shared Memory – System V
int shmget(key_t key, int size, int flags)Obtains an identifier to an existing shared memory or creates a new one. “key” can be IPC_PRIVATE (which creates a new unique
identifier), or an existing identifier. ftok() can be used to generate a number based on a filename.
“size” its the shared memory size in bytes “flags”, normal mode flags. When ORed with IPC_CREAT creates
a new one.
int shmctl(int shmid, int cmd, struct shmid_ds* buff)Provides a variety of control operations on the shared memory. “shmid” is the value returned by shmget() “cmd” is the command (most usually: IPC_RMID to remove it) “buff” a structure used in some control operations
![Page 84: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/84.jpg)
84
Shared Memory – System V (2)
int shmat(int shmid, const void* where, int flags)Maps a certain shared memory region into the current process address space. “shmid” represents the shared memory identifier “shmid”
returned by shmget() “where” represents an unused address space location where to
map the shared memory (normally, use NULL) “flags” represent different ways of doing the mapping (typically
0)
int shmdt(const void* where)Unmaps a certain shared memory region from the current address space. “where” represents an unused address space location where to
map the shared memory (normally, use NULL)
![Page 85: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/85.jpg)
85
How does attaching work
Address Space A Address Space B
“Real Memory”
int id = shmget(1234, 2, IPC_CREAT|0777)
char* p = shmat(id, NULL, 0);
p[0] = 19;
int id = shmget(1234, 2, 0777)
char* p = shmat(id, NULL, 0);
p[1] = 59;
p
p(id.. 324)
19
19
19
59
5959
![Page 86: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/86.jpg)
86
What’s wrong with this routine?
P1 P2
print_work(a, 12); print_work(b, 65);
![Page 87: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/87.jpg)
87
Synchronization – Semaphores
A semaphore is a synchronization object Controlled access to a counter (a value) Two operations are supported: wait() and post()
wait() If the semaphore is positive, decrement it and continue If not, block the calling process (thread)
post() Increment the semaphore value If there was any process (thread) blocked due to the semaphore, unblock
one of them.
5
P1
value
P6 P3 NULLblockedprocesslist
“A semaphore”
![Page 88: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/88.jpg)
88
Corrected version
Mutual Exclusion: Only one process can be in here!
You always have to synchronize, even if you areonly reading or writing one byte!
![Page 89: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/89.jpg)
89
Synchronization – Semaphores
System V Semaphores Works with semaphore arrays semget(), semctl(), semop() A little bit hard to use by themselves
Use a library to encapsulate them!
POSIX Semaphores Quite easy to use sem_init(), sem_close(), sem_post(), sem_wait() Also work with threads! But... in Linux, they only work with threads (kernel 2.4)
Semaphores are very useful for other things besides mutual exclusion: they can be used to count things!
![Page 90: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/90.jpg)
90
semaphore.h
My Semaphore Library
![Page 91: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/91.jpg)
91
Example – Producer/Consumer
A producer puts elements on a finite buffer. If the buffer is full, it blocks until there’s space.
The consumer retrieves elements. If the buffer is empty, it blocks until something comes along.
We will need three semaphores One to count the empty slots One to count the full slots One to provide for mutual exclusion to the shared buffer
Producer Consumer
![Page 92: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/92.jpg)
92
Example – Producer/Consumer
Producer Consumer
empty full
read_pos write_pos
put_element(e) { sem_wait(empty); sem_wait(mutex); buf[write_pos] = e; write_pos = (write_pos+1) % N; sem_post(mutex); sem_post(full);}
mutex
get_element() { sem_wait(full); sem_wait(mutex); e = buf[read_pos]; read_pos = (read_pos+1) % N; sem_post(mutex); sem_post(empty); return e;}
![Page 93: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/93.jpg)
93
The result of executing it!
![Page 94: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/94.jpg)
94
And the main part of its code...
void producer() { for (int i=TOTAL_VALUES; i>0; i--) { printf("[PRODUCER] Writing %d\n", i); put_element(i); }}
void consumer() { for (int i=0; i<TOTAL_VALUES; i++) { int e = get_element(); printf("[CONSUMER] Retrieved %d\n", e); sleep(1); } terminate();}
void main(int argc, char* argv[]) { init();
if (fork() == 0) { producer(); exit(0); } else { consumer(); exit(0); }}
![Page 95: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/95.jpg)
95
put_element() and get_element()
void put_element(int e) { sem_wait(sem, EMPTY); sem_wait(sem, MUTEX);
buf[write_pos] = e; write_pos = (write_pos+1) % N;
sem_post(sem, MUTEX); sem_post(sem, FULL);}
int get_element() { sem_wait(sem, FULL); sem_wait(sem, MUTEX);
int e = buf[read_pos]; read_pos = (read_pos+1) % N;
sem_post(sem, MUTEX); sem_post(sem, EMPTY);
return e;}
![Page 96: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/96.jpg)
96
init() and terminate()
int sem, shmid;int write_pos, read_pos;int* buf;
void init() { sem = sem_get(3, 0); sem_setvalue(sem, EMPTY, N); // N is the number of slots sem_setvalue(sem, FULL, 0); sem_setvalue(sem, MUTEX, 1);
write_pos = read_pos = 0;
shmid = shmget(IPC_PRIVATE, N*sizeof(int), IPC_CREAT|0700); buf = (int*) shmat(shmid, NULL, 0);}
void terminate() { sem_close(sem); shmctl(shmid, IPC_RMID, NULL);}
![Page 97: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/97.jpg)
97
Remember
Always cleanup...
![Page 98: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/98.jpg)
98
Implementation of semlib (semlib.c)
![Page 99: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/99.jpg)
99
Implementation of semlib (semlib.c) (2)
![Page 100: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/100.jpg)
100
Implementation of semlib (semlib.c) (3)
![Page 101: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/101.jpg)
InterprocessCommunication in Unix
Paulo MarquesDepartment of Informatics EngineeringUniversity of [email protected]
2006
/200
7
POSIX Threads
![Page 102: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/102.jpg)
102
Threads
Flows of execution inside of a program They share all the address space of a process Each thread has its own stack and local variables
(even so, they can access other’s threads variables)Process
Thread 1 Thread 2 Thread 3
![Page 103: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/103.jpg)
103
Why use threads?
They are very light weight compared to processes Light context switches Fast to create and terminate Fast to synchronize
Much easier to program than shared memory! Everything is already shared Be careful to synchronize accesses!
![Page 104: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/104.jpg)
104
POSIX Threads – Thread Management
![Page 105: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/105.jpg)
105
Simple thread creation example (simple_thread.c)
![Page 106: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/106.jpg)
106
Running the example
gcc –lpthread –D_REENTRANT –Wall fich.c –o fich
![Page 107: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/107.jpg)
107
Compiling with threads
Linux
-D_REENTRANT is quite important in LinuxThreads (Kernel 2.4) It instructs the compiler to use special re-entrant routine
functions If you don’t... it ONLY appears to work, until you get in
trouble!
gcc –lpthread –D_REENTRANT –Wall fich.c –o fich
Beware: Many routines are not re-entrant, they cannot be directly used with threads since they use common storage in an unsynchronized way (e.g. stktok())!
In some cases, there are re-entrant versions (e.g. strtok_r()). Check the manual! Don’t trust common sense.
![Page 108: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/108.jpg)
108
Example of a non-reentrant routine
What happens if this is called from two different threads at the same time??
![Page 109: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/109.jpg)
109
Things to beware of
Doesn’t work, “i” is on the stack and constantly changing
Doesn’t work, (1) after main() dies, its variables disappear – race condition with the starting threads; (2) main() dies everything dies!
![Page 110: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/110.jpg)
110
If you need to terminate the main() thread...
This is OK!
Note: the other threads continue to execute.
![Page 111: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/111.jpg)
111
Synchronization
Mutexes Provide mutual exclusion zones between threads In fact, these are just fast binary semaphores
POSIX Semaphores Used to signal events across threads Used to count objects in an synchronized way
Condition Variables Allow a thread to block or to notify others on any
condition Semaphores are a kind of condition variable:
the implicit condition is the semaphore being greater than 0
![Page 112: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/112.jpg)
112
Mutexes
![Page 113: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/113.jpg)
113
POSIX Semaphores
![Page 114: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/114.jpg)
114
Producer/Consumer Revisited
Producer Consumer
Producer
Producer
![Page 115: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/115.jpg)
115
prod_cons_threads.c
![Page 116: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/116.jpg)
116
prod_cons_threads.c (2)
![Page 117: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/117.jpg)
117
Which results in...
![Page 118: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/118.jpg)
118
Synchronization – Condition Variables
Condition variables allow the programmer to suspend or notify a thread on any condition!
![Page 119: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/119.jpg)
119
Synchronization – Condition Variables (2)
Important rule: A condition variable always has an associated mutex. Always check the condition variable in mutual exclusion.
The mutex must be locked.
How does it work?Makes thread Acheck its conditionagain
![Page 120: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/120.jpg)
120
Synchronization – Condition Variables (3)
The thread tests a condition in mutual exclusion. If the condition is false, pthread_cond_wait() atomically releases de mutex AND waits until someone signals that the condition should be tested again.
When the condition is signaled AND the mutex is available, pthread_cond_wait() atomically reacquires the mutex AND releases the thread.
pthread_cond_signal() indicates that exactly one blocked thread should test the condition again. Note that this is note a semaphore. If there is no thread blocked, the “signal” is lost.
If all threads should re-check the condition, use pthread_cond_broadcast(). Since a mutex is involved, each one will test it one at a time, in mutual exclusion.
![Page 121: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/121.jpg)
121
Example
Suppose a buffer that can hold a maximum of N elements. When it is full, it should immediately be emptied. While the buffer is being emptied, no thread can put things into it.
Producer
CleanerProducer
Producer
![Page 122: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/122.jpg)
122
bounded_buffer.c
![Page 123: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/123.jpg)
123
bounded_buffer.c (2)
![Page 124: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/124.jpg)
124
With 3 producers and one cleaner...
![Page 125: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/125.jpg)
125
Condition Variables – Rules (!)
The condition must always be tested with a while loop, never an if! Being unlocked out of a condition variable only means that the condition must be re-checked, not that it is true
The condition must always be checked and signaled inside a locked mutex.
While condition() may betrue while Thread B is executing,something may happen betweenthe time that the condition is signaledand Thread A is unblock (e.g. anotherthread may change the condition)
![Page 126: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/126.jpg)
126
Synchronization – Some basic rules...
Never Interlock waits! Locks should always be taken in the same order Always release locks in the reverse order they have
been taken
sem_wait(A)sem_wait(B)
// Critical Section
sem_post(B)sem_post(A)
sem_wait(B)sem_wait(A)
// Critical Section
sem_post(A)sem_post(B)
Deadlock!
One way to assure that you always take locks in the same order is to create a lock hierarchy. I.e. associate a number to each lock using a table and always lock in increasing order using that table as reference (index).
![Page 127: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/127.jpg)
127
Synchronization – Some basic rules... (2)
Sometimes it is not possible to know each order to take when locking (or using semaphores) Example: you are using
two resources owned by the operating system. They are controlled by locks. You cannot be sure another application is not using exactly the same resources and locking in reverse order.
In that case, use pthread_mutex_trylock() or sem_trywait() and back off if you are unsuccessful. Allow the system to make
progress and not deadlock
![Page 128: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/128.jpg)
128
Synchronization – Some basic rules... (3)
Mutexes are for implementing mutual exclusion, not for signaling across threads! One the thread that has locked a mutex can unlock it. Not doing
so will probably result in a core dump! To signal across threads use semaphores!
lock(&m)
unlock(&m)
lock(&m)
unlock(&m)
CORRECT!
lock(&m)
unlock(&m)
INCORRECT!(Use a semaphore for this!)
A B A B
(in mutual exclusion)
(in mutual exclusion)
(blocked)
![Page 129: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/129.jpg)
129
Synchronization – Some basic rules... (4)
Don’t mess with thread priorities unless you really need to. Although apparently “correct” and “logical” in design, it’s quite
easy to make a system deadlock, live-lock or some threads to starve.
![Page 130: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/130.jpg)
130
The Mars PathFinder Problem
Priority Inversion Problem (in Mars Path Finder): Low priority thread locks a
semaphore. High priority thread starts to
execute and tries to lock the same semaphore. It’s suspended since it cannot violate the other thread lock.
Medium priority threads comes to execute and preempts the low priority one. Since it doesn’t need the semaphore, it continues to execute.
Meanwhile the high priority one is starving. After a while, a watchdog timer detects that the high priority one is not executing and resets the machine.
A
B
C
starts toexecuteand getsthe lock
starts toexecute
tries to get the lock and is suspended
continuesto execute
is preempted asmedium prioritygets to execute
watchdog timer resets the machine as the high priorityone doesn’t get toexecute
![Page 131: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/131.jpg)
131
To Learn More
Advanced Programming in the UNIX Environment, 2nd Edition by W. Richard Stevens, Stephen A. Rago
Addison-Wesley, June 2005
UNIX Network Programming, Volume 2: Interprocess Communications, 2nd Ed. by W. Richard Stevens
Prentice Hall, August 1998
Unix Systems Programming: Communication, Concurrency and Threads, 2nd Edition by Kay Robbins, Steve Robbins
Prentice Hall, June 2003
![Page 132: Interprocess Communication in Unix Paulo Marques Department of Informatics Engineering University of Coimbra pmarques@dei.uc.pt 2006/2007 An Introduction](https://reader037.vdocuments.us/reader037/viewer/2022103022/56649d3e5503460f94a17c68/html5/thumbnails/132.jpg)
132
IMPORTANT NOTICE
YOU ARE FREE TO USE THIS MATERIAL FOR YOUR PERSONAL LERNING OR REFERENCE, DISTRIBUTE IT AMONG COLLEGUES OR EVEN USE IT FOR TEACHING CLASSES. YOU MAY EVEN MODIFY IT, INCLUDING MORE INFORMATION OR CORRECTING STANDING ERRORS.
THIS RIGHT IS GIVEN TO YOU AS LONG AS YOU KEEP THIS NOTICE AND GIVE PROPER CREDIT TO THE AUTHOR. YOU CANNOT REMOVE THE REFERENCES TO THE AUTHOR OR TO THE INFORMATICS ENGINEERING DEPARTMENT OF THE UNIVERSITY OF COIMBRA.
(c) 2005 – Paulo Marques, [email protected]