2.3 InterProcess Communication (IPC). IPC methods ► Signals ► Mutex (MUTual EXclusion) ► Semaphores ► Shared memory ► Memory mapped files ► Pipes & named.

Slides:



Advertisements
Similar presentations
Florida State UniversityCOP5570 – Advanced Unix Programming IPC mechanisms Pipes Sockets System V IPC –Message Queues –Semaphores –Shared Memory.
Advertisements

Inter-Process Communication: Message Passing Tore Larsen Slides by T. Plagemann, Pål Halvorsen, Kai Li, and Andrew S. Tanenbaum.
Operating Systems Lecture 7.
Concurrency: Mutual Exclusion and Synchronization Chapter 5.
CSCC69: Operating Systems
Chapter 6: Process Synchronization
Silberschatz, Galvin and Gagne ©2009 Operating System Concepts – 8 th Edition, Chapter 6: Process Synchronization.
Process Synchronization. Module 6: Process Synchronization Background The Critical-Section Problem Peterson’s Solution Synchronization Hardware Semaphores.
©2009 Operačné systémy Procesy. 3.2 ©2009 Operačné systémy Process in Memory.
XSI IPC Message Queues Semaphores Shared Memory. XSI IPC Each XSI IPC structure has two ways to identify it An internal (within the Kernel) non negative.
2.3 InterProcess Communication (IPC) Part A. IPC methods 1. Signals 2. Mutex (MUTual EXclusion) 3. Semaphores 4. Shared memory 5. Memory mapped files.
System V IPC (InterProcess Communication) Messages Queue, Shared Memory, and Semaphores.
Avishai Wool lecture Introduction to Systems Programming Lecture 4 Inter-Process / Inter-Thread Communication.
Process Process: the UNIX abstraction of a stand-along computer that manages resources (memory, CPU, I/O resources) comprising a running program. Processes.
Introduction to Operating Systems – Windows process and thread management In this lecture we will cover Threads and processes in Windows Thread priority.
Inter Process Communication:  It is an essential aspect of process management. By allowing processes to communicate with each other: 1.We can synchronize.
Synchronization Principles. Race Conditions Race Conditions: An Example spooler directory out in 4 7 somefile.txt list.c scores.txt Process.
CS444/CS544 Operating Systems Synchronization 2/19/2007 Prof. Searleman
UNIX IPC CSE 121 Spring 2003 Keith Marzullo. CSE 121 Spring 2003Review of Concurrency2 Creating a UNIX process A process is created by making an exact.
Process in Unix, Linux and Windows CS-3013 C-term Processes in Unix, Linux, and Windows CS-3013 Operating Systems (Slides include materials from.
Client Server Model The client machine (or the client process) makes the request for some resource or service, and the server machine (the server process)
Threads© Dr. Ayman Abdel-Hamid, CS4254 Spring CS4254 Computer Network Architecture and Programming Dr. Ayman A. Abdel-Hamid Computer Science Department.
1 Outline Processes Threads Inter-process communication (IPC) Classical IPC problems Scheduling.
Processes in Unix, Linux, and Windows CS-502 Fall Processes in Unix, Linux, and Windows CS502 Operating Systems (Slides include materials from Operating.
1 Race Conditions/Mutual Exclusion Segment of code of a process where a shared resource is accessed (changing global variables, writing files etc) is called.
2.3 InterProcess Communication (IPC) Part C. IPC methods 1. Signals 2. Mutex (MUTual EXclusion) 3. Semaphores 4. Shared memory 5. Memory mapped files.
Assignment 3 A Client/Server Application: Chatroom.
Inter-Process Communication Mechanisms CSE331 Operating Systems Design.
Sirak Kaewjamnong Computer Network Systems
Server Sockets: A server socket listens on a given port Many different clients may be connecting to that port Ideally, you would like a separate file descriptor.
Chapter 3: Processes. 3.2 Silberschatz, Galvin and Gagne ©2005 Operating System Concepts - 7 th Edition, Feb 7, 2006 Process Concept Process – a program.
S -1 Shared Memory. S -2 Motivation Shared memory allows two or more processes to share a given region of memory -- this is the fastest form of IPC because.
Lecture 3 Process Concepts. What is a Process? A process is the dynamic execution context of an executing program. Several processes may run concurrently,
System V IPC Provides three mechanisms for InterProcess Communication (IPC) : Messages : exchange messages with any process or server. Semaphores : allow.
2.3 InterProcess Communication (IPC)
The kernel considers each program running on your system to be a process A process lives as it executes, with a lifetime that may be short or long A process.
Florida State UniversityCOP5570 – Advanced Unix Programming Today’s topics System V Interprocess communication (IPC) mechanisms –Message Queues –Semaphores.
1 Shared Memory. 2  Introduction  Creating a Shared Memory Segment  Shared Memory Control  Shared Memory Operations  Using a File as Shared Memory.
CE Operating Systems Lecture 13 Linux/Unix interprocess communication.
CSCE 515: Computer Network Programming UDP Socket Wenyuan Xu Department of Computer Science and Engineering.
Scis.regis.edu ● CS 468: Advanced UNIX Class 5 Dr. Jesús Borrego Regis University 1.
IPC Programming. Process Model Processes can be organized into a parent-child hierarchy. Consider the following example code: /* */
Week Fourteen Agenda Announcements Final Exam True/False -100 questions (1 point per question) Multiple Choice - 40 questions (2 points per question)
Socket Programming Lab 1 1CS Computer Networks.
Operating Systems Process Creation
Signals and Signal Processing CIS 370 Lab 7 Umass Dartmouth.
1 Signals (continued) CS 241 April 9, 2012 University of Illinois.
2.3 interprocess communcation (IPC) (especially via shared memory & controlling access to it)
UNIX Signals * POSIX-Defined Signals * Signaling Processes * Signal Mask * sigaction * kill and sigaction * alarm * Interval Timers * POSIX.1b Timers *
2.3 InterProcess Communication (IPC). IPC methods ► Signals ► Mutex (MUTual EXclusion) ► Semaphores ► Shared memory ► Memory mapped files ► Pipes & named.
Interprocess Communication Mechanisms. IPC Signals Pipes System V IPC.
Background Concurrent access to shared data may result in data inconsistency Maintaining data consistency requires mechanisms to ensure the orderly execution.
Message Queues. Unix IPC Package ● Unix System V IPC package consists of three things – Messages – allows processes to send formatted data streams to.
S -1 Processes. S -2 wait and waitpid (11.2) Recall from a previous slide: pid_t wait( int *status ) wait() can: (a) block; (b) return with status; (c)
Semaphores Reference –text: Tanenbaum ch
Lecture 3 TCP and UDP Sockets CPE 401 / 601 Computer Network Systems slides are modified from Dave Hollinger.
Mutual Exclusion -- Addendum. Mutual Exclusion in Critical Sections.
Transmitter Interrupts Review of Receiver Interrupts How to Handle Transmitter Interrupts? Critical Regions Text: Tanenbaum
Case Study: Pthread Synchronization Dr. Yingwu Zhu.
UNIX signals.
Interprocess Communication Race Conditions
Assignment 3 A Client/Server Application: Chatroom
Semaphores Reference text: Tanenbaum ch
Chapter 3: Process Concept
Chapter 5 (part 1) TCP Client /Server Example By: Lim Meng Hui.
UDP Sockets Programming
CSC Advanced Unix Programming, Fall 2015
Inter-Process Communication ENCE 360
Concurrency: Mutual Exclusion and Process Synchronization
Semaphores Reference text: Tanenbaum ch
Presentation transcript:

2.3 InterProcess Communication (IPC)

IPC methods ► Signals ► Mutex (MUTual EXclusion) ► Semaphores ► Shared memory ► Memory mapped files ► Pipes & named pipes ► Sockets ► Message queues ► MPI (Message Passing Interface) ► Barriers

IPC methods 1. thread to thread 2. process to process (both on same system) 3. system to system (i.e., processes on different systems)

IPC methods between threads ► Mutex ► Semaphores

IPC methods between processes ► Signals ► Shared memory ► Memory mapped files ► Pipes & named pipes ► Message queues

IPC methods between systems ► Sockets ► MPI (Message Passing Interface)  Barriers

Signals

Signals ► software interrupts ► async ► can be recognized or ignored

Signals #include #include //defn. of signal handler function typedef void (*sighandler_t)(int); //function call to establish a signal handler sighandler_t signal ( int signum, sighandler_t handler ); What is this?

Remember... char* ptr1, ptr2; is not the same as char* ptr1; char* ptr2; It really means char *ptr1, ptr2; Use char *ptr1, *ptr2; instead.

Allowed signals (see kill –l) 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 32) SIGRTMIN 33) SIGRTMIN+1 34) SIGRTMIN+2 35) SIGRTMIN+3 36) SIGRTMIN+4 37) SIGRTMIN+5 38) SIGRTMIN+6 39) SIGRTMIN+7 40) SIGRTMIN+8 41) SIGRTMIN+9 42) SIGRTMIN+10 43) SIGRTMIN+11 44) SIGRTMIN+12 45) SIGRTMIN+13 46) SIGRTMIN+14 47) SIGRTMIN+15 48) SIGRTMAX-15 49) SIGRTMAX-14 50) SIGRTMAX-13 51) SIGRTMAX-12 52) SIGRTMAX-11 53) SIGRTMAX-10 54) SIGRTMAX-9 55) SIGRTMAX-8 56) SIGRTMAX-7 57) SIGRTMAX-6 58) SIGRTMAX-5 59) SIGRTMAX-4 60) SIGRTMAX-3 61) SIGRTMAX-2 62) SIGRTMAX-1 63) SIGRTMAX ► Also see man 7 signal for a lengthier description.

As reported by kill -l on SunOS/Solaris (Sun’s Unix) ► HUP, INT, QUIT, ILL, TRAP, ABRT, EMT, FPE, KILL, BUS, SEGV, SYS, PIPE, ALRM, TERM, USR1, USR2, CLD, PWR, WINCH, URG, POLL, STOP, TSTP, CONT, TTIN, TTOU, VTALRM, PROF, XCPU, XFSZ, WAITING, LWP, FREEZE, THAW, CANCEL, LOST, XRES, JVM1, JVM2, RTMIN, RTMIN+1, RTMIN+2, RTMIN+3, RTMAX-3, RTMAX-2, RTMAX-1, RTMAX

Sending a signal to a process ► Use the kill command (see man kill).  kill [ -s signal | -p ] [ -a ] [ -- ] pid...  kill -l [ signal ] ► Use the kill function (see man 2 kill) #include #include int kill ( pid_t pid, int sig );

Signal example code //define the signal hander function void myHandler ( int signalNo ) { …}… //define the signal handler // (typically done once in main) signal( SIGCHLD, myHandler );

Mutex Used to control access to shared memory and other resources, in general.

Race condition ► An error where  one process may wait forever  or other inconsistencies may result ► Occurs when two or more processes are reading or writing some shared data ► Applies to threads as well ► The final result depends on process or thread runs, precisely when they run, and in what order they run. ► Difficult to debug and reproduce errors.

Critical region/section ► Part of program where shared memory is accessed  Must be identified ► mutual exclusion (mutex)  method to exclude other processes from using a shared variable until our process is finished with it

Process cooperation rules: 1. No two processes can be in their critical sections at the same time. 2. Make no timing assumptions. ► My code is faster/shorter; my processor is faster. ► My priority is higher. ► The probability is small for us both processes to do this at the same time. 3. (progress) A process should not be blocked from entering a critical region if all other processes are outside the critical region. 4. (bounded wait) No process should have to wait forever to get into its critical region.

Mutual exclusion w/ busy waiting Methods to implement mutex: 1.Disable interrupts 2.Lock variables 3.Strict alternation 4.Peterson’s solution 5.TSL instruction

Mutex method 1: disable interrupts ► OK for (and used by) OS  Consideration for MP systems ► NOT OK for apps  Why not?

Mutex method 2: lock vars ► software method ► employs single, shared lock variable initially = 0 ► uses busy wait  spin lock

Mutex method 2: lock vars shared int x=0; //wait for lock while (x!=0) ; //  note the empty statement x=1; //get lock //critical section … //end critical section x=0; //release lock ► Doesn’t work (w/out hardware support). ► What about performance?

Mutex method 3: strict alternation

► Software ► Problem: violates process cooperation rule #3.  Because in strict alternation, a process can be blocked from entering its C.S. by a process NOT in its C.S. ► In general, a process can’t be in it’s C.S. 2x in a row. ► The 2 processes must be running at about the same speed.

Mutex method 4: Peterson’s (sofware) soln.

Mutex method 4: Peterson’s (software) soln.

Mutex method 4: Peterson’s soln. (software)

Mutex method 4: Peterson’s (sofware) soln. ► Works, but suffers from busy wait. ► Has been generalized to more than 2 processes (but the above is only for 2).

Mutex method 5: TSL instruction ► TSL = Test and Set Locked ► TSL RX, LOCK  RX = register; LOCK = memory location  Step 1: read contents of LOCK into RX  Step 2: sets LOCK to 1  Indivisible instruction (non interruptible)  Memory, not cache  Locks memory bus (so other processors can’t access/change LOCK) ► IA32 xchg and lock instructions

Mutex method 5: TSL instruction

Priority inversion problem ► an unexpected consequence of busy wait ► given H (a high priority job), and L (low priority job) ► scheduling algorithm: whenever H is ready to run, L is preempted and H is run.

Priority inversion problem H runs… H blocks on I/O I/O completes H runs … H attempts to enter C.S. H busy waits forever! L is ready to run L runs … L enters C.S. … … L is preempted......

Using mutex (provided by OS) ► Simpler than semaphore ► Two states: locked or unlocked ► Functions:  Declare mutex variable  Initialize mutex variable (just once)  lock ---> C.S. ---> unlock

#include #include … pthread_mutex_t mutex; ///< declare global (i.e., not inside of any function) … //perform this one-time initialization (usually in main) int ret = pthread_mutex_init( &::mutex, NULL ); if (ret) { perror( "main: mutex init error" ); exit(-1); } … //lock in thread code ret = pthread_mutex_lock( &::mutex ); if (ret) { printf( "%d: mutex lock error \n", tp->whoAmI ); } //critical section here //critical section here //unlock in thread code pthread_mutex_unlock( &::mutex );

#include #include … CRITICAL_SECTION g_cs; … //perform this one-time initialization (usually in main) InitializeCriticalSection( &g_cs ); … //lock in thread code EnterCriticalSection( &g_cs ); //critical section here //critical section here //unlock in thread code LeaveCriticalSection( &g_cs );

Problem: ► Modify filter program to also determine overall min and max of input data. 1. Can you do this with global variables? 2. Can you do this without global variables? ► Which method requires mutex?

Semaphores

(Bounded) Producer-Consumer ► A producer produces some item and stores it in a warehouse. ► A consumer consumes an item by removing an item from the warehouse. ► Notes:  The producer must pause production if the warehouse fills up (bounded).  If the warehouse is empty, the consumer must wait for something to be produced.

(Bounded) producer- consumer problem Danger, Will Robinson (a shared variable)!

(Bounded) Producer-consumer problem ► Buffer is initially empty. ► Consumer checks count. It’s 0. ► Scheduler interrupts consumer (puts consumer on ready queue). ► Producer runs.  Insert data into buffer.  Count is 1 so producer wakes up consumer.  But consumer is not asleep just yet! (The scheduler interrupted it right before the call to sleep().)  Producer keeps inserting data into buffer until it’s full. Then producer goes to sleep! ► Scheduler runs consumer. Consumer thinks count=0 so it goes to sleep! ► Both sleep forever!

Semaphores ► Invented by Dutch computer scientist Edsger Dijkstra. ► Two basic operations: 1.Up ► increments the value of the semaphore ► historically denoted as V (also known as signal) 2.Down ► decrements the value of the semaphore ► P (also known as wait)

Semaphores Types: 1.POSIX ► Shared only among threads. 2.Windows ► system-wide. ► Can be system-wide. 3.System V ► Can be shared according to user-group-other (can be system-wide).

Binary semaphores = mutex ► Create semaphore and initialize it to 1.  1 = unlocked  0 = locked ► Then to use this as a mutex:  down ► c.s.  up

POSIX SEMAPHORES

POSIX Semaphores (shared among threads only) #include #include 1. int sem_init ( sem_t* sem, int pshared, unsigned int value ); 2. int sem_wait ( sem_t* sem ); 3. int sem_trywait ( sem_t* sem ); 4. int sem_post ( sem_t* sem ); 5. int sem_getvalue ( sem_t* sem, int* sval ); 6. int sem_destroy ( sem_t* sem );

POSIX Semaphores int sem_init ( sem_t* sem, int pshared, unsigned int value );  initialize  pshared must be 0 on (some versions of) Linux ► semaphore is not shared by processes  Value is initial value for semaphore.

POSIX Semaphores int sem_wait ( sem_t* sem );  down (if possible/blocking) int sem_trywait ( sem_t* sem );  nonblocking down ► Blocking?

POSIX Semaphores int sem_post ( sem_t* sem );  up (nonblocking) int sem_getvalue ( sem_t* sem, int* sval );  get the current semaphore value int sem_destroy ( sem_t* sem );  finish using the semaphore

WINDOWS SEMAPHORES

Windows Semaphores HANDLE WINAPI CreateSemaphore ( __in_opt LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, __in_opt LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, __in LONG lInitialCount, __in LONG lInitialCount, __in LONG lMaximumCount, __in LONG lMaximumCount, __in_opt LPCTSTR lpName __in_opt LPCTSTR lpName); DWORD WINAPI WaitForSingleObject ( __in HANDLE hHandle, __in HANDLE hHandle, __in DWORD dwMilliseconds __in DWORD dwMilliseconds ); //decrements count by 1 BOOL WINAPI ReleaseSemaphore ( __in HANDLE hSemaphore, __in LONG lReleaseCount, __out_opt LPLONG lpPreviousCount ); //increments count by lReleaseCount BOOL WINAPI CloseHandle ( __in HANDLE hObject );

SYSTEM V SEMAPHORES

System V Semaphores (system-wide) #include #include 1. int semget ( key_t key, int nsems, int semflg );  create/access existing 2. int semctl ( int semid, int semnum, int cmd,... );  delete from system 3. int semop ( int semid, struct sembuf* sops, unsigned nsops );  used for up and down

Create/access existing //using the key, get the semaphore id const int sid = semget( mySemKey, 1, IPC_CREAT | 0700 ); if (sid==-1) { perror( "semget " ); perror( "semget " ); exit( -1 ); exit( -1 );} printf( "sem id=%d \n", sid ); create if necessary system-wide permissions (In C/C++, octal values start with 0.) system-wide unique number

Create/access existing //using the key, get the semaphore id const int sid = semget( mySemKey, 1, IPC_CREAT | 0700 ); alternative (#include ): const int sid = semget( mySemKey, 1, IPC_CREAT | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); create if necessary system-wide permissions (In C/C++, octal values start with 0.)

Access and delete //using the key, get the semaphore id const int sid = semget( mySemKey, 1, 0700 ); if (sid==-1) { perror( "semget " ); perror( "semget " ); exit( -1 ); exit( -1 );} printf( "sem id=%d \n", sid ); //delete the semaphore semctl( sid, 0, IPC_RMID, 0 );

Down function static void down ( const int whichSid ) { struct sembuf sem_lock; struct sembuf sem_lock; sem_lock.sem_num = 0; //semaphore number: 0 = first sem_lock.sem_num = 0; //semaphore number: 0 = first sem_lock.sem_op = -1; //semaphore operation sem_lock.sem_op = -1; //semaphore operation sem_lock.sem_flg = 0; //operation flags sem_lock.sem_flg = 0; //operation flags if (semop(whichSid, &sem_lock, 1) == -1) { if (semop(whichSid, &sem_lock, 1) == -1) { perror("semop "); perror("semop "); exit(-1); exit(-1); }}

Up function static void up ( const int whichSid ) { struct sembuf sem_unlock; struct sembuf sem_unlock; sem_unlock.sem_num = 0; //semaphore number: 0 = first sem_unlock.sem_num = 0; //semaphore number: 0 = first sem_unlock.sem_op = 1; //semaphore operation sem_unlock.sem_op = 1; //semaphore operation sem_unlock.sem_flg = 0; //operation flags sem_unlock.sem_flg = 0; //operation flags if (semop(whichSid, &sem_unlock, 1) == -1) { if (semop(whichSid, &sem_unlock, 1) == -1) { perror("semop"); perror("semop"); exit(-1); exit(-1); }}

Solution to (bounded) producer- consumer problem using semaphores (via up() and down()). Note: 3 semaphores (one used as mutex)!

(BOUNDED) PRODUCER- CONSUMER DEMO bounded.h,boundedProducer.cpp,boundedConsumer.cpp

UNBOUNDED PRODUCER- CONSUMER

(Unbounded) producer-consumer ► Every time the producer process runs, it produces one item. ► Every time the consumer runs, it consumes one item (or waits until one is available, and then consumes it).

//unbounded producer int main ( int argc, char* argv[] ) { //using the key, get the semaphore id //using the key, get the semaphore id const int sid = semget( mySemKey, 1, IPC_CREAT | 0700 ); const int sid = semget( mySemKey, 1, IPC_CREAT | 0700 ); if (sid==-1) { if (sid==-1) { perror( "semget " ); perror( "semget " ); exit( -1 ); exit( -1 ); } printf( "sem id=%d \n", sid ); printf( "sem id=%d \n", sid ); puts( "producing" ); puts( "producing" ); struct sembuf sem_unlock; struct sembuf sem_unlock; sem_unlock.sem_num = 0; //semaphore number: 0 = first sem_unlock.sem_num = 0; //semaphore number: 0 = first sem_unlock.sem_op = 1; //semaphore operation sem_unlock.sem_op = 1; //semaphore operation sem_unlock.sem_flg = 0; //operation flags sem_unlock.sem_flg = 0; //operation flags if (semop(sid, &sem_unlock, 1) == -1) { if (semop(sid, &sem_unlock, 1) == -1) { perror("semop "); perror("semop "); exit(-1); exit(-1); } puts( "produced" ); puts( "produced" ); return 0; return 0;} Unbounded producer basically does an up() to indicate production.

//consumer int main ( int argc, char* argv[] ) { //using the key, get the semaphore id //using the key, get the semaphore id const int sid = semget( mySemKey, 1, IPC_CREAT | 0700 ); const int sid = semget( mySemKey, 1, IPC_CREAT | 0700 ); if (sid==-1) { if (sid==-1) { perror( "semget " ); perror( "semget " ); exit( -1 ); exit( -1 ); } printf( "sem id=%d \n", sid ); printf( "sem id=%d \n", sid ); puts( "consuming" ); puts( "consuming" ); struct sembuf sem_lock; struct sembuf sem_lock; sem_lock.sem_num = 0; //semaphore number: 0 = first sem_lock.sem_num = 0; //semaphore number: 0 = first sem_lock.sem_op = -1; //semaphore operation sem_lock.sem_op = -1; //semaphore operation sem_lock.sem_flg = 0; //operation flags sem_lock.sem_flg = 0; //operation flags if (semop(sid, &sem_lock, 1) == -1) { if (semop(sid, &sem_lock, 1) == -1) { perror("semop "); perror("semop "); exit(-1); exit(-1); } puts( "consumed" ); puts( "consumed" ); return 0; return 0;} Consumer basically does a down() to indicate consumption.

(UNBOUNDED) PRODUCER- CONSUMER DEMO mySemKey.h, producer.cpp, consumerWait.cpp, consumerNoWait.cpp, bigProducer.cpp, delete.cpp

Shared Memory

Shared memory ► Shared memory operations  shmget ► allocates a shared memory segment  shmctl ► allows the user to receive information on a shared memory segment, set the owner, group, and permissions of a shared memory segment, or destroy a segment

Shared memory ► Shared memory operations  shmat ► attaches the shared memory segment (identified by shmid) to the address space of the calling process  shmdt ► detaches the shared memory segment (located at the address specified by shmaddr) from the address space of the calling process

Shared memory ► From the Linux sem_init man page:  The pshared argument indicates whether this semaphore is to be shared between the threads of a process, or between processes. 1. If pshared has the value 0, then the semaphore is shared between the threads of a process, and should be located at some address that is visible to all threads (e.g., a global variable, or a variable allocated dynamically on the heap). 2. If pshared is nonzero, then the semaphore is shared between processes, and should be located in a region of shared memory.

Memory mapped files

“There comes a time when you want to read and write to and from files so that the information is shared between processes. Think of it this way: two processes both open the same file and both read and write from it, thus sharing the information. The problem is, sometimes it's a pain to do all those fseek()s and stuff to get around. Wouldn't it be easier if you could just map a section of the file to memory, and get a pointer to it? Then you could simply use pointer arithmetic to get (and set) data in the file. Well, this is exactly what a memory mapped file is. And it's really easy to use, too. A few simple calls, mixed with a few simple rules, and you're mapping like a mad-person.”

Memory mapped files ► mmap  void* mmap ( void* start, size_t length, int prot, int flags, int fd, off_t offset );  map length bytes starting at offset offset from the file specified by the file descriptor fd into memory, preferably at address start

Memory mapped files ► munmap  int munmap ( void* start, size_t length );  The munmap system call deletes the mappings for the specified address range, and causes further references to addresses within the range to generate invalid memory references.  The region is also automatically unmapped when the process is terminated.  On the other hand, closing the file descriptor does not unmap the region.

Pipes and named pipes

Pipes

More Pipes

Too many pipes!

// Excerpt from "Linux Programmer's Guide - Chapter 6." // (C)opyright , Scott Burkett #include #include int main ( int argc, char* argv[] ) { int fd[2], nbytes; int fd[2], nbytes; pid_t childpid; pid_t childpid; char string[] = "Hello, world!\n", readbuffer[80]; char string[] = "Hello, world!\n", readbuffer[80]; pipe( fd ); pipe( fd ); if ((childpid = fork()) == -1) { if ((childpid = fork()) == -1) { perror( "fork" ); perror( "fork" ); exit( 1 ); exit( 1 ); } if (childpid == 0) { //Child process closes up input side of pipe if (childpid == 0) { //Child process closes up input side of pipe close( fd[0] ); close( fd[0] ); /* Send "string" through the output side of pipe */ /* Send "string" through the output side of pipe */ write( fd[1], string, (strlen(string)+1) ); write( fd[1], string, (strlen(string)+1) ); } else { //Parent process closes up output side of pipe } else { //Parent process closes up output side of pipe close( fd[1] ); close( fd[1] ); /* Read in a string from the pipe */ /* Read in a string from the pipe */ nbytes = read( fd[0], readbuffer, sizeof(readbuffer) ); nbytes = read( fd[0], readbuffer, sizeof(readbuffer) ); printf( "parent: received string: %s", readbuffer ); printf( "parent: received string: %s", readbuffer ); } return 0; return 0;} Pipes via pipe()

// Excerpt from "Linux Programmer's Guide - Chapter 6." // (C)opyright , Scott Burkett #include #include #define MAXSTRS 5 int main ( int argc, char* argv[] ) { FILE *pipe_fp; FILE *pipe_fp; char *strings[MAXSTRS] = { "echo", "bravo", "alpha", "charlie", "delta"}; char *strings[MAXSTRS] = { "echo", "bravo", "alpha", "charlie", "delta"}; /* Create one way pipe line with call to popen() */ /* Create one way pipe line with call to popen() */ if (( pipe_fp = popen("sort", "w")) == NULL) { if (( pipe_fp = popen("sort", "w")) == NULL) { perror("popen"); perror("popen"); exit(1); exit(1); } /* Processing loop */ /* Processing loop */ for (int cntr=0; cntr<MAXSTRS; cntr++) { for (int cntr=0; cntr<MAXSTRS; cntr++) { fputs(strings[cntr], pipe_fp); fputs(strings[cntr], pipe_fp); fputc('\n', pipe_fp); fputc('\n', pipe_fp); } /* Close the pipe */ /* Close the pipe */ pclose(pipe_fp); pclose(pipe_fp); return 0; return 0;} Pipes via popen() Any valid shell command. Can be “w” or “r”.

// Excerpt from "Linux Programmer's Guide - Chapter 6" // (C)opyright , Scott Burkett #include #include #define MAXSTRS 5 int main ( int argc, char* argv[] ) { FILE *pipe_fp; FILE *pipe_fp; char *strings[MAXSTRS] = { "echo", "bravo", "alpha", "charlie", "delta"}; char *strings[MAXSTRS] = { "echo", "bravo", "alpha", "charlie", "delta"}; /* Create one way pipe line with call to popen() */ /* Create one way pipe line with call to popen() */ if (( pipe_fp = popen("sort", "w")) == NULL) { if (( pipe_fp = popen("sort", "w")) == NULL) { perror("popen"); perror("popen"); exit(1); exit(1); } /* Processing loop */ /* Processing loop */ for (int cntr=0; cntr<MAXSTRS; cntr++) { for (int cntr=0; cntr<MAXSTRS; cntr++) { fputs(strings[cntr], pipe_fp); fputs(strings[cntr], pipe_fp); fputc('\n', pipe_fp); fputc('\n', pipe_fp); } /* Close the pipe */ /* Close the pipe */ pclose(pipe_fp); pclose(pipe_fp); return 0; return 0;} Pipes via popen() Any valid shell command. Can be “w” or “r”. How would I modify this to have obtain the sorted information?

// Excerpt from "Linux Programmer's Guide - Chapter 6" // (C)opyright , Scott Burkett #include #include #define MAXSTRS 5 int main ( int argc, char* argv[] ) { FILE *pipe_fp; FILE *pipe_fp; char *strings[MAXSTRS] = { "echo", "bravo", "alpha", "charlie", "delta"}; char *strings[MAXSTRS] = { "echo", "bravo", "alpha", "charlie", "delta"}; /* Create one way pipe line with call to popen() */ /* Create one way pipe line with call to popen() */ if (( pipe_fp = popen("sort > junk.dat", "w")) == NULL) { if (( pipe_fp = popen("sort > junk.dat", "w")) == NULL) { perror("popen"); perror("popen"); exit(1); exit(1); } /* Processing loop */ /* Processing loop */ for (int cntr=0; cntr<MAXSTRS; cntr++) { for (int cntr=0; cntr<MAXSTRS; cntr++) { fputs(strings[cntr], pipe_fp); fputs(strings[cntr], pipe_fp); fputc('\n', pipe_fp); fputc('\n', pipe_fp); } /* Close the pipe */ /* Close the pipe */ pclose(pipe_fp); pclose(pipe_fp); return 0; return 0;} Pipes via popen() Any valid shell command. Can be “w” or “r”. How would I modify this to have obtain the sorted information? Better but is junk.dat unique?

Named pipes ► Named pipes  Use mkfifo command. (What is a FIFO?)  Example ► mkfifo mypipe ► ls –l mypipe  p rw ggrevera ggrevera 0 Oct 5 21:30 mypipe ► ls –l > mypipe  Hangs! Why?  Ctrl-c ► ls –l > mypipe & ► cat < mypipe  Doesn’t hang! Why?

Named pipes ► Named pipes  Use mkfifo command. (What is a FIFO?)  Example ► mkfifo mypipe ► ls –l mypipe  p rw ggrevera ggrevera 0 Oct 5 21:30 mypipe ► ls –l > mypipe  Hangs! Why? Because it waits for the reader.  Ctrl-c ► ls –l > mypipe & ► cat < mypipe  Doesn’t hang! Why? Because the reader executes.  Output on next slide.

Output from named pipe example ► ls –l > mypipe & ► cat < mypipe total rwx ggrevera ggrevera Oct 5 20:45 a.out drwx ggrevera ggrevera 4096 Feb csc4025 drwx ggrevera ggrevera 4096 Oct 3 09:59 csc4035 -rw ggrevera ggrevera Sep 6 12:52 csc4035.tar -rw ggrevera ggrevera 891 Dec dir.cpp... -rw ggrevera ggrevera 283 Oct 5 20:44 sig.cpp [1]+ Done ls -l >mypipe Why did this finish? Because the reader read everything.

Sockets

Sockets

Sockets – client-side Steps: 1.socket()  creates an endpoint for communication and returns a descriptor 2.connect()  attempts to make a connection to another socket 3.call read() and/or write()  similar to an ordinary file

#include #include static void error ( char* msg ) { perror( msg ); perror( msg ); exit( 0 ); exit( 0 );} int main ( int argc, char* argv[] ) { if (argc < 3) { if (argc < 3) { fprintf( stderr, "usage: %s hostname port \n", argv[0] ); fprintf( stderr, "usage: %s hostname port \n", argv[0] ); exit( 0 ); exit( 0 ); } int portno = atoi( argv[2] ); int portno = atoi( argv[2] ); int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); if (sockfd < 0) error( "ERROR opening socket“ ); if (sockfd < 0) error( "ERROR opening socket“ );... Sockets – client-side (writes a message and reads a response)

Sockets – client-side... struct hostent* server = gethostbyname( argv[1] ); //does host exist? struct hostent* server = gethostbyname( argv[1] ); //does host exist? if (server == NULL) { if (server == NULL) { fprintf( stderr, "ERROR, no such host \n" ); fprintf( stderr, "ERROR, no such host \n" ); exit( 0 ); exit( 0 ); } struct sockaddr_in serv_addr; struct sockaddr_in serv_addr; bzero( &serv_addr, sizeof(serv_addr) ); //move 0’s to buffer bzero( &serv_addr, sizeof(serv_addr) ); //move 0’s to buffer serv_addr.sin_family = AF_INET; serv_addr.sin_family = AF_INET; //copy binary data from buffer to buffer //copy binary data from buffer to buffer bcopy( server->h_addr, &serv_addr.sin_addr.s_addr, server->h_length ); bcopy( server->h_addr, &serv_addr.sin_addr.s_addr, server->h_length ); serv_addr.sin_port = htons( portno ); //host byte order to network b.o. serv_addr.sin_port = htons( portno ); //host byte order to network b.o. if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) error( "ERROR connecting“ ); error( "ERROR connecting“ );...

Sockets – client-side... printf("Please enter the message: "); printf("Please enter the message: "); char buffer[256]; char buffer[256]; bzero( buffer, sizeof(buffer) ); bzero( buffer, sizeof(buffer) ); fgets( buffer, sizeof(buffer)-1, stdin ); fgets( buffer, sizeof(buffer)-1, stdin ); int n = write( sockfd, buffer, strlen(buffer) ); int n = write( sockfd, buffer, strlen(buffer) ); if (n < 0) if (n < 0) error("ERROR writing to socket"); error("ERROR writing to socket"); bzero( buffer, sizeof(buffer) ); bzero( buffer, sizeof(buffer) ); n = read( sockfd, buffer, sizeof(buffer)-1 ); n = read( sockfd, buffer, sizeof(buffer)-1 ); if (n < 0) error("ERROR reading from socket"); if (n < 0) error("ERROR reading from socket"); printf( "%s \n", buffer ); printf( "%s \n", buffer ); return 0; return 0;}

Sockets – client-side (complete code) #include #include static void error ( char* msg ) { perror( msg ); perror( msg ); exit( 0 ); exit( 0 );} int main ( int argc, char* argv[] ) { if (argc < 3) { if (argc < 3) { fprintf( stderr, "usage: %s hostname port \n", argv[0] ); fprintf( stderr, "usage: %s hostname port \n", argv[0] ); exit( 0 ); exit( 0 ); } int portno = atoi( argv[2] ); int portno = atoi( argv[2] ); int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); if (sockfd < 0) error("ERROR opening socket"); if (sockfd < 0) error("ERROR opening socket"); struct hostent* server = gethostbyname(argv[1]); struct hostent* server = gethostbyname(argv[1]); if (server == NULL) { if (server == NULL) { fprintf( stderr, "ERROR, no such host \n" ); fprintf( stderr, "ERROR, no such host \n" ); exit( 0 ); exit( 0 ); } struct sockaddr_in serv_addr; struct sockaddr_in serv_addr; bzero( &serv_addr, sizeof(serv_addr) ); bzero( &serv_addr, sizeof(serv_addr) ); serv_addr.sin_family = AF_INET; serv_addr.sin_family = AF_INET; bcopy( server->h_addr, &serv_addr.sin_addr.s_addr, server->h_length ); bcopy( server->h_addr, &serv_addr.sin_addr.s_addr, server->h_length ); serv_addr.sin_port = htons( portno ); serv_addr.sin_port = htons( portno ); if (connect(sockfd, (struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0) if (connect(sockfd, (struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0) error("ERROR connecting"); error("ERROR connecting"); printf("Please enter the message: "); printf("Please enter the message: "); char buffer[256]; char buffer[256]; bzero( buffer, sizeof(buffer) ); bzero( buffer, sizeof(buffer) ); fgets( buffer, sizeof(buffer)-1, stdin ); fgets( buffer, sizeof(buffer)-1, stdin ); int n = write(sockfd,buffer,strlen(buffer)); int n = write(sockfd,buffer,strlen(buffer)); if (n < 0) if (n < 0) error("ERROR writing to socket"); error("ERROR writing to socket"); bzero( buffer, sizeof(buffer) ); bzero( buffer, sizeof(buffer) ); n = read( sockfd, buffer, sizeof(buffer)-1 ); n = read( sockfd, buffer, sizeof(buffer)-1 ); if (n < 0) error("ERROR reading from socket"); if (n < 0) error("ERROR reading from socket"); printf( "%s \n", buffer ); printf( "%s \n", buffer ); return 0; return 0;}

Sockets – server-side

Steps: 1.socket()  creates an endpoint for communication and returns a descriptor 2.bind()  this is called "assigning a name to a socket“  when a socket is created with socket, it exists in a name space (address family) but has no name assigned 3.listen()  To accept connections, a socket is first created with socket(), a willingness to accept incoming connections and a queue limit for incoming connections are specified with listen, and then the connections are accepted with accept(). 4.Repeat forever: 1. accept() 2. fork() a child process that performs reads and/or writes as per ordinary file.

int accept ( int s, struct sockaddr* addr, socklen_t* addrlen ); ► It extracts the first connection request on the queue of pending connections, creates a new connected socket with mostly the same properties as s, and allocates a new file descriptor for the socket, which is returned. ► The newly created socket is no longer in the listening state. The original socket s is unaffected by this call.

/** * \file server2.cpp * \file server2.cpp * \author george j. grevera * \author george j. grevera * \brief A simple server in the internet domain using TCP. Runs on * \brief A simple server in the internet domain using TCP. Runs on * polaris (but not on scott). * polaris (but not on scott). * To compile: g++ -o server2.exe server2.cpp -lsocket * To compile: g++ -o server2.exe server2.cpp -lsocket */ */ #include #include static const int Port = 8090; static const bool Verbose = true; // int main ( int argc, char* argv[] ) { //create an endpoint for communication //create an endpoint for communication if (Verbose) puts( "socket()" ); if (Verbose) puts( "socket()" ); int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); assert( sockfd != -1 ); assert( sockfd != -1 );… Sockets – server-side

… //assign a name to the socket //assign a name to the socket struct sockaddr_in serv_addr; struct sockaddr_in serv_addr; memset( &serv_addr, 0, sizeof(serv_addr) ); memset( &serv_addr, 0, sizeof(serv_addr) ); serv_addr.sin_family = AF_INET; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons( Port ); serv_addr.sin_port = htons( Port ); if (Verbose) printf( "bind() port %d. \n", Port ); if (Verbose) printf( "bind() port %d. \n", Port ); int ret = bind( sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr) ); int ret = bind( sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr) ); assert( ret != -1 ); assert( ret != -1 );… Sockets – server-side

… //a willingness to accept incoming connections and a queue //a willingness to accept incoming connections and a queue // limit for incoming connections are specified with listen // limit for incoming connections are specified with listen if (Verbose) puts( "listen()" ); if (Verbose) puts( "listen()" ); ret = listen( sockfd, 5 ); ret = listen( sockfd, 5 ); assert( ret != -1 ); assert( ret != -1 );… Sockets – server-side

… for ( ; ; ) { for ( ; ; ) { //extract the first connection request on the queue of pending connections, create a new connected socket with //extract the first connection request on the queue of pending connections, create a new connected socket with // mostly the same properties as s, and allocate a new file descriptor for the socket, which is returned // mostly the same properties as s, and allocate a new file descriptor for the socket, which is returned if (Verbose) puts( "parent: accept()" ); if (Verbose) puts( "parent: accept()" ); struct sockaddr_in cli_addr; struct sockaddr_in cli_addr; socklen_t clilen = sizeof( cli_addr ); socklen_t clilen = sizeof( cli_addr ); int newsockfd = accept( sockfd, (struct sockaddr*)&cli_addr, &clilen ); assert( newsockfd != -1 ); int newsockfd = accept( sockfd, (struct sockaddr*)&cli_addr, &clilen ); assert( newsockfd != -1 ); if (Verbose) puts( "parent: fork()" ); if (Verbose) puts( "parent: fork()" ); int pid = fork(); int pid = fork(); if (pid==0) { if (pid==0) { if (Verbose) puts( "child: after fork()" ); if (Verbose) puts( "child: after fork()" ); close( sockfd ); close( sockfd ); char buffer[ 256 ]; char buffer[ 256 ]; memset( buffer, 0, sizeof(buffer) ); memset( buffer, 0, sizeof(buffer) ); puts( "child: read()" ); puts( "child: read()" ); int n = read( newsockfd, buffer, sizeof(buffer)-1 ); int n = read( newsockfd, buffer, sizeof(buffer)-1 ); assert( n != -1 ); assert( n != -1 ); printf( "child: Here is the message: %s\n", buffer ); printf( "child: Here is the message: %s\n", buffer ); puts( "child: write()" ); puts( "child: write()" ); n = write( newsockfd, "I got your message", strlen("I got your message") ); n = write( newsockfd, "I got your message", strlen("I got your message") ); assert( n != -1 ); assert( n != -1 ); close( newsockfd ); close( newsockfd ); exit( 0 ); exit( 0 ); } close( newsockfd ); close( newsockfd ); } return 0; return 0;} Sockets – server-side

Sockets – server-side (complete code) /** * \file server2.cpp * \file server2.cpp * \author george j. grevera * \author george j. grevera * \brief A simple server in the internet domain using TCP. Runs on * \brief A simple server in the internet domain using TCP. Runs on * polaris (but not on scott). * polaris (but not on scott). * To compile: g++ -o server2.exe server2.cpp -lsocket * To compile: g++ -o server2.exe server2.cpp -lsocket */ */ #include #include static const int Port = 8090; static const bool Verbose = true; // int main ( int argc, char* argv[] ) { //create an endpoint for communication //create an endpoint for communication if (Verbose) puts( "socket()" ); if (Verbose) puts( "socket()" ); int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); assert( sockfd != -1 ); assert( sockfd != -1 ); //assign a name to the socket //assign a name to the socket struct sockaddr_in serv_addr; struct sockaddr_in serv_addr; memset( &serv_addr, 0, sizeof(serv_addr) ); memset( &serv_addr, 0, sizeof(serv_addr) ); serv_addr.sin_family = AF_INET; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons( Port ); serv_addr.sin_port = htons( Port ); if (Verbose) printf( "bind() port %d. \n", Port ); if (Verbose) printf( "bind() port %d. \n", Port ); int ret = bind( sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr) ); int ret = bind( sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr) ); assert( ret != -1 ); assert( ret != -1 ); //a willingness to accept incoming connections and a queue //a willingness to accept incoming connections and a queue // limit for incoming connections are specified with listen // limit for incoming connections are specified with listen if (Verbose) puts( "listen()" ); if (Verbose) puts( "listen()" ); ret = listen( sockfd, 5 ); ret = listen( sockfd, 5 ); assert( ret != -1 ); assert( ret != -1 ); for ( ; ; ) { for ( ; ; ) { //extract the first connection request on the queue of //extract the first connection request on the queue of // pending connections, create a new connected socket with // pending connections, create a new connected socket with // mostly the same properties as s, and allocate a new file // mostly the same properties as s, and allocate a new file // descriptor for the socket, which is returned // descriptor for the socket, which is returned if (Verbose) puts( "parent: accept()" ); if (Verbose) puts( "parent: accept()" ); struct sockaddr_in cli_addr; struct sockaddr_in cli_addr; socklen_t clilen = sizeof( cli_addr ); socklen_t clilen = sizeof( cli_addr ); int newsockfd = accept( sockfd, (struct sockaddr*)&cli_addr, &clilen ); int newsockfd = accept( sockfd, (struct sockaddr*)&cli_addr, &clilen ); assert( newsockfd != -1 ); assert( newsockfd != -1 ); if (Verbose) puts( "parent: fork()" ); if (Verbose) puts( "parent: fork()" ); int pid = fork(); int pid = fork(); if (pid==0) { if (pid==0) { if (Verbose) puts( "child: after fork()" ); if (Verbose) puts( "child: after fork()" ); close( sockfd ); close( sockfd ); char buffer[ 256 ]; char buffer[ 256 ]; memset( buffer, 0, sizeof(buffer) ); memset( buffer, 0, sizeof(buffer) ); puts( "child: read()" ); puts( "child: read()" ); int n = read( newsockfd, buffer, sizeof(buffer)-1 ); int n = read( newsockfd, buffer, sizeof(buffer)-1 ); assert( n != -1 ); assert( n != -1 ); printf( "child: Here is the message: %s\n", buffer ); printf( "child: Here is the message: %s\n", buffer ); puts( "child: write()" ); puts( "child: write()" ); n = write( newsockfd, "I got your message", n = write( newsockfd, "I got your message", strlen("I got your message") ); strlen("I got your message") ); assert( n != -1 ); assert( n != -1 ); close( newsockfd ); close( newsockfd ); exit( 0 ); exit( 0 ); } close( newsockfd ); close( newsockfd ); } return 0; return 0;}//

Message queues

#include #include ► MSGMAX defines the max length of a message (~8K). ► Define your message(s).  You may define many different messages of different lengths. struct myMessage { long mtype;//message type …//body of message (you decide) };

Message queues ► msgget - begin accessing (and create if necessary) a message queue int msgget ( key_t key, int msgflg ); ► msgsnd - send (enqueue) a message int msgsnd ( int msqid, struct msgbuf* msgp, size_t msgsz, int msgflg ); ► msgrcv - receive (dequeue) a message ssize_t msgrcv ( int msqid, struct msgbuf* msgp, size_t msgsz, long msgtyp, int msgflg ); ► msgctl - misc. message queue control

Other IPC mechanisms: ► Monitors  A collection of procedures, variables, and data structures that are all grouped together in a special kind of module or package.  Only one process can be active in a monitor at any instant.

Monitors and the (bounded) producer- consumer problem

Other IPC mechanisms: ► Monitors ► Message passing (MPI) ► Barriers