62
cs431-cotter 1 Linux Process Linux Process Synchronization Synchronization Tanenbaum 10.3, 2.3 Linux man pthread_mutex_init, etc. The Linux Programming Interface - Kerrisk Interprocess Communications in Linux - Gray

CS431 Linux Process Sync 12 Bw

  • Upload
    sciby

  • View
    12

  • Download
    0

Embed Size (px)

DESCRIPTION

Linux Process

Citation preview

  • cs431-cotter*Linux Process SynchronizationTanenbaum 10.3, 2.3Linux man pthread_mutex_init, etc.The Linux Programming Interface - KerriskInterprocess Communications in Linux - Gray

    cs431-cotter

  • cs431-cotter*cs431-cotterOverviewLinux IPCSignalAlarmWaitSemaphore (named and unnamed)MutexPipe ( named and unnamed)MessagesShared Memory

    cs431-cotter

  • cs431-cotter*Linux IPCKernel SynchronizationUse wait_queue for kernel process syncAllows multiple processes to wait for a single eventServes as basic component to build user process syncProcess synchronizationSignal - most primitiveSemaphorePipesetc.

    cs431-cotter

  • cs431-cotter*Figure 10-5. The signals required by POSIX.Signals in LinuxTanenbaum, Modern Operating Systems 3 e, (c) 2008 Prentice-Hall, Inc. All rights reserved. 0-13-6006639

    cs431-cotter

  • cs431-cotter*Signals1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGEMT 8) SIGFPE 9) SIGKILL10) SIGBUS11) SIGSEGV12) SIGSYS13) SIGPIPE14) SIGALRM15) SIGTERM16) SIGURG17) SIGSTOP18) SIGTSTP19) SIGCONT20) SIGCHLD21) SIGTTIN22) SIGTTOU23) SIGIO24) SIGXCPU25) SIGXFSZ26) SIGVTALRM27) SIGPROF28) SIGWINCH29) SIGINFO30) SIGUSR131) SIGUSR2

    Current versions of Linux support 64 signals (real time signals added). See: man 2 signal, man 2 sigaction man 7 signal

    cs431-cotter

  • cs431-cotter*Signal HandlerSignal function can have different behavior based on the version of UNIX.sigaction (signal_to_catch, new_action, old_action)struct sigaction {void * sa_handler; // What function do we call?sigset_t mask; // Mask of signals to block when calledint sa_flags; // Special flags to set.};

    cs431-cotter

  • cs431-cotter*AlarmAllows user program to set an external timer (measured in seconds). If alarm times out, sigalrm will be sent to the calling process.Use: sigaction (SIGALRM, sigaction, NULL);

    cs431-cotter

  • cs431-cotter*Sig_alarm.cpp#include #include #include #include using namespace std;

    #define MAXLINE 128static void sig_alarm(int signo);

    int main () {int n;char line [MAXLINE];struct sigaction act;memset (&act, 0, sizeof(act));act.sa_handler = &sig_alarm;act.sa_flags = SA_RESTART;

    cs431-cotter

  • cs431-cotter*Sig_alarm.cppif ((sigaction(SIGALRM, &act, NULL)) < 0){cout
  • cs431-cotter*sig_alarm.cpp Output[rcotter@kc-sce-450p2 cs431]$ g++ -o sigtest sig_alarm3.cpp[rcotter@kc-sce-450p2 cs431]$ ./sigtestThis is a testThis is a test[rcotter@kc-sce-450p2 cs431]$ ./sigtestThis is another ### We got the alarm signal!! ###testThis is another test[rcotter@kc-sce-450p2 cs431]$

    cs431-cotter

  • cs431-cotter*wait( )#include #include

    pid_t wait (int *status);

    The wait function suspends execution of the current pro cess until a child has exited, or until a signal is deliv ered whose action is to terminate the current process or to call a signal handling function. If a child has already exited by the time of the call (a so-called "zom bie" process), the function returns immediately. Any sys tem resources used by the child are freed.

    cs431-cotter

  • cs431-cotter*waittest1.c#include #include #include #include #include #include

    int main(){pid_tpid;intstatus;printf("Forking child process...\n");if ((pid = fork()) < 0){printf("fork failed!\n");exit(1);}

    cs431-cotter

  • cs431-cotter*waittest1.celse if (pid == 0){ /* child process */ sleep(5);printf("Child process is shutting down\n");exit(7);}else { /* parent process */ if (wait (&status) != pid) {printf("Wait returned invalid pid\n");exit(1);}if (WIFEXITED(status))printf("Normal Termination. Exit value %2d\n",WEXITSTATUS(status));else {printf("Abnormal termination!!!\n");exit(1);}printf("Parent shutting down...\n");exit(0);}}

    cs431-cotter

  • cs431-cotter*waittest.c outputrcotter@debian-alpha:~$ gcc -o waittest waittest1.c rcotter@debian-alpha:~$ ./waittestForking child process...Child process is shutting downNormal Termination. Exit value 7Parent shutting down...rcotter@debian-alpha:~$

    cs431-cotter

  • cs431-cotter*SemaphoresPOSIX version of semaphores#include classic semaphore implementationSystem V version of semaphores#include Enhanced version of semaphores to include sets

    cs431-cotter

  • cs431-cotter*POSIX (unnamed) Semaphoressem_t empty, full;

    int sem_init ((sem_t *sem, int pshared, unsigned int value));sem_t (address of semaphore to be initializedpshared (is semaphore shared?) SHARED, 0initial valueint sem_wait ((sem_t *sem));sem_t (address of semaphore to be waited for)int sem_post ((sem_t *sem));sem_t (address of semaphore to be signalled)

    cs431-cotter

  • cs431-cotter*Example Semaphore fragmentsem_t checker;

    Main Program {declare variables...sem_init(&checker, 0, 1);pthread_create(&pid1, NULL, job, NULL);pthread_create(&pid2, NULL, job, NULL);pthread_join(pid1, NULL);pthread_join(pid2, NULL);:}job() { while (work to do..) {sem_wait (&checker);do stuff...sem_post(&checker);do other stuff.... }}

    cs431-cotter

  • *cs431-cotter*POSIX Named Semaphoressem_t empty, full; sem_t *sem_open (char *name, int oflag, [mode_t mode[, [int init_value]);char *name (must begin with /)[O_CREAT], [O_EXCL], 0 (new or existing semaphore?)mode (if new, mod bits 0xxx)Init_value (if new, initial value of semaphore)int sem_wait ((sem_t *sem));sem_t (address of semaphore to be waited for)int sem_post ((sem_t *sem));sem_t (address of semaphore to be signalled)int sem_close (sem_t *sem);int sem_unlink(char *name);int sem_getvalue (sem_t *sem, int *val);Named semaphore has kernel persistenceCreated in /dev/shm

  • *Named Semaphore exampleproducer - Consumer#define SHARED 0#define BUFSIZE 20

    int terminatethreads=0;

    void *Producer(void *); /* the two threads */void *Consumer(void *);

    sem_t *Sempty, *Sfull, *Sflag; /* the semaphore descriptors */char sem1[] = "/semEmpty"; //The names for the semaphoreschar sem2[] = "/semFull";char sem3[] = "/semFlag";int buf[BUFSIZE]; /* shared buffer */int mycount;

    static void sig_alarm(int signo);

  • *Named Semaphore exampleint main(int argc, char *argv[]) { int ans; time_t now; pthread_t pid, cid; time (&now); srand (now); if (signal (SIGALRM, sig_alarm) == SIG_ERR) {cout
  • *Named Semaphore example cout
  • *Named Semaphore examplevoid *Producer(void *arg) { int produced=0; int input = 0; cout
  • *Named Semaphore examplevoid *Consumer(void *arg) { int consumed= 0; cout
  • cs431-cotter*Figure 2-30. Some of the Pthreads calls relating to mutexes.Mutexes in Pthreads (1)Tanenbaum, Modern Operating Systems 3 e, (c) 2008 Prentice-Hall, Inc. All rights reserved. 0-13-6006639

    cs431-cotter

  • cs431-cotter*Figure 2-31. Some of the Pthreads calls relating to condition variables.Mutexes in Pthreads (2)Tanenbaum, Modern Operating Systems 3 e, (c) 2008 Prentice-Hall, Inc. All rights reserved. 0-13-6006639

    cs431-cotter

  • cs431-cotter*Figure 2-32. Using threads to solve the producer-consumer problem.Mutexes in Pthreads (3)Tanenbaum, Modern Operating Systems 3 e, (c) 2008 Prentice-Hall, Inc. All rights reserved. 0-13-6006639

    cs431-cotter

  • *Linux Interprocess CommunicationsUnnamed PipesNamed PipesMessage QueuesShared Memory

  • cs431-cotter*Unnamed pipes (pipes)Allow communications between related processes.UnidirectionalUsed from command line to link commandsls -l | morecat -n myfile.cpp | lpr Used in programs to communicate between processespipetest.cpp

    cs431-cotter

  • cs431-cotter*Pipe Commandspopen FILE * popen (const char* cmd, const char * type);type = r, wpclose int pclose (FILE * stream);

    #include

    cs431-cotter

  • cs431-cotter*Named PipesPermanent objectsAvailable to processes that can access the filespace (same system or on a shared file system)Processes do not have to be related.

    cs431-cotter

  • cs431-cotter*Named Pipes (FIFO)int mkfifo(const char *name, mode_t mode);return is a file descriptorname is the name of the pipemode is the permissions for the pipe (0666 = RDWR all)

    int open(const char * name, int flags);flags = O_RDONLY, O_WRONLY, O_RDWR

    ssize_t read(int fd, void *buf, size_t count);

    ssize_t write(int fd, void *buf, size_t count);

    cs431-cotter

  • cs431-cotter*Message QueuesA linked list of messagesMessage queue has kernel persistenceSupports asynchronous communications.Messages are stored in the queue, independent of the sender (sender can close queue without losing messages).Receiver can retrieve messages at a later time.Messages have a priorityHigher priority messages are retrieved first (POSIX)Max priority is 32768

    cs431-cotter

  • cs431-cotter*Message QueuesMessage Queue Capacity(Can be set higher by root)Max msgs: 10 /queueMax Msg Size: 8192Max # of Queues: 256Queues are created in their own virtual message queue file system (mqueue)Can be mounted to view (and manipulate) queuesmkdir /dev/mqueuemount t mqueue none /dev/mqueue

    cs431-cotter

  • cs431-cotter*Create and/or open a msg queuemqd_t mq_open (qName, flags, [mode], [attributes]);qName: Name of the queue to open / createMust be of the form /qName.flags: How queue will be opened/created.O_RDONLY | O_WRONLY | O_RDWR , [O_CREAT] )mode: File permissions for queue:S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP, S_IROTH, S_IWOTHattributes: Limits for the queue: struct mq_attrlong mq_flags: 0 | O_NONBLOCK (read queue non-blocking?)long mq_maxmsg: max msgs in queuelong mq_msgsize: max msg sizelong mq_curmsgs: How many messages are currently in queue?

    cs431-cotter

  • cs431-cotter*Send a message to a queuemqd_t mq_send (queue_descr, msg, size, prior);Queue_descr: Like a file descriptor. Value returned from mq_open.Msg: a pointer to a character buffer for the messageSize: (size_t) size of message in bytesPrior: (unsigned int) priority of message

    Returns 0 on success, -1 on error

    cs431-cotter

  • cs431-cotter*Receive a message from a queuessize_t mq_receive (queue_descr, msg, size, prior);Queue_descr: Like a file descriptor. Value returned from mq_open.Msg: a pointer to a character buffer for the messageSize: (size_t) size of buffer in bytesPrior: (*unsigned int) priority of message read.

    Returns number of bytes read (or -1 on error)

    cs431-cotter

  • cs431-cotter*Get attributes of a Queuemqd_t mq_getattr (queue_descr, *struct mq_attr);Queue_descr: Like a file descriptor. Value returned from mq_open.*struct mq_attr: Pointer to struct that will return attributes of the opened queuelong mq_flags: 0 | O_NONBLOCK (read queue non-blocking?)long mq_maxmsg: max msgs in queuelong mq_msgsize: max msg sizelong mq_curmsgs: How many messages are currently in queue?

    Returns 0 on success, -1 on error

    cs431-cotter

  • cs431-cotter*Removing (unlinking) a queueMqd_t mq_unlink ( qName);qName: Name of queueQueue is removed from the message queue file system. Any messages still in the queue are lost. Returns 0 on success, -1 on error

    cs431-cotter

  • cs431-cotter*mq_send(Note: All error checking has been removed from the code to focus on the details of message queue handling)

    #include (also many other included header files)#define NAMESIZE 25#define MSGCOUNT 5#define MSGSIZE 512using namespace std;int main (int argc, char **argv) { int lSize, bufSize, stat, i; char qName[NAMESIZE]; char ans[5]; mqd_t mqd; struct mq_attr qAtr; unsigned int prio = 3; char buf[MSGSIZE];

    cs431-cotter

  • cs431-cotter*mq_send - 2 strncpy(qName, "/", 2); strncat (qName, argv[1], lSize+1); qAtr.mq_maxmsg = MSGCOUNT; qAtr.mq_msgsize = MSGSIZE; mqd = mq_open(qName, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH, &qAtr); do { cout prio; stat = mq_send(mqd, buf, bufSize, prio);

    cs431-cotter

  • cs431-cotter*mq_send - 3 if (stat == 0) cout
  • cs431-cotter*mq_recv - 1Note: Most of the error checking code has been removed to focus on the message queue portions of the code.#include also many other #include files#define NAMESIZE 25#define MSGCOUNT 25#define MSGSIZE 512#define BUFSIZE 9000using namespace std;int main (int argc, char **argv){ int lSize, bufSize, stat, msgcount, i, j; char qName[NAMESIZE]; mqd_t mqd; struct mq_attr qAtr; unsigned int prio = 3; char buf[BUFSIZE];

    cs431-cotter

  • cs431-cotter*mq_recv - 2 strncpy(qName, "/", 2); strncat (qName, argv[1], lSize+1); mqd = mq_open(qName, O_RDONLY); mq_getattr(mqd, &qAtr); msgcount = qAtr.mq_curmsgs; cout
  • cs431-cotter*Sample send Output[rcotter@kc-sce-450p2 msgQ]$ ./mq_send nuQMessage Queue name (/nuQ) is 4 charactersWe opened the queue!What message do you want to send? This is my first test messageWhat is the message priority? 2Send was successfulSend another message (yes/no)?yesWhat message do you want to send? This is my second test messageWhat is the message priority? 4Send was successfulSend another message (yes/no)?yesWhat message do you want to send? This is my third test messageWhat is the message priority? 1Send was successfulSend another message (yes/no)?no[rcotter@kc-sce-450p2 msgQ]$

    cs431-cotter

  • cs431-cotter*Sample recv Output[rcotter@kc-sce-450p2 msgQ]$ ./mq_recv nuQFile name (/nuQ) is 4 charactersWe opened the queue!There are currently 3 messages in queuemsg: This is my second test message; Prio: 4msg: This is my first test message; Prio: 2msg: This is my third test message; Prio: 1[rcotter@kc-sce-450p2 msgQ]$

    cs431-cotter

  • cs431-cotter*Shared MemoryAllows 2 or more processes to share the same main memory spaceMemory can be allocated as blocks (pages) of memoryMemory can be mapped as a file that is available in memory to multiple processes

    cs431-cotter

  • cs431-cotter*Shared MemoryP1P2P3

    cs431-cotter

  • *Shared Memory

  • cs431-cotter*Shared Memory UsageCreate a shared memory segmentOne or more processes attach to itProcesses read and/or write to the segment. Note that process sync is critical.All processes detach from shared memoryOne process removes (de-allocates) the segment

    cs431-cotter

  • cs431-cotter*Create a Shared Memory SegmentRequires: , int shmget (key_t, int size, int shmflg);Key_t:Shared memory segment number identifier (e.g. 15, 1000). Can be used to create a new segment or ensure that an existing segment still exists.IPC_PRIVATE- special variable that guarantees that a new segment will be createdSize:Size of the memory segment. Should be a multiple of th ememory page size (typically 4096 in Linux).Shmflg:Flags that control behavior of the new segment. IPC_CREAT, IPC_EXCL, mode bits(9)Return (int)Shared memory ID used to access or modify the shared memory

    cs431-cotter

  • cs431-cotter*Shared Memory Segment Limitsipcs -lMaximum segment sizeSHMMAX32768 kbytesMinimum segment sizeSHMMIN1 byteTotal maximum # of segmentsSHMMNI4096Total maximum shared memorySHMALL8388608 kbytes

    cs431-cotter

  • cs431-cotter*Control Shared Memoryint shmctl (shmid, cmd, struct shmid_ds *buf);shmid: Shared memory identifier. (Value returned from shmget())cmd: IPC_STAT return status information about the shared memory in buf.IPC_SET modify the shared memory based on parameters in buf (can only change UID and mode bits)IPC_RMID Remove (deallocate) the shared memory segment specified in shmid.IPC_LOCK lock the shared memory segment in memory (dont swap out).IPC_UNLOCK release the lock on shared memory

    cs431-cotter

  • cs431-cotter*Attach to a Shared Memory Segmentvoid * shmat (shmid, shmaddr, shmflg);shmid: Shared memory identifier. (Value returned from shmget())shmaddr: Address where shared memory should attach to process.If 0, OS picks a suitable addressIf not 0 and SHM_RND flag is set, bind address will be given address, rounded down to a page boundaryIf not 0 and SHM_RND is not set, address must be a page boundaryshmflg: SHM_RND round down the attach address to a page boundarySHM_RDONLY open for read only. Process must have read access to the segmentReturn value: Address at which the shared memory is mapped.

    cs431-cotter

  • cs431-cotter*Detach from Shared Memory Segmentint shmdt (shmaddr);shmaddr address at which shared memory is attachedreturn 0 for success, -1 for fail

    cs431-cotter

  • *Shared Memory Example#include , etc#define SHM_SIZE 2048#define ARRAYSIZE50#define LOOPCOUNT1000000#define PCOUNT3

    using namespace std;

    int main( ) { int shmid, i, j, k, sum, *shm, *myNum; int pid, procNum, n1, n2; intmyNumbers[ARRAYSIZE]; int s[3]; //seeds for rand();char sem1[] = /semBlock;sem_t*Scount;for (i = 0; i < ARRAYSIZE; i++) //Fill array with 0-49. Sum = 1225 myNumbers[i] = i;

  • *Shared Memory Exampleif ((shmid=shmget(IPC_PRIVATE,SHM_SIZE,IPC_CREAT|0660))< 0) { perror("shmget fail"); return 1; } if ((shm = (int *)shmat(shmid, 0, 0)) == (int *) -1) { perror("shmat : parent"); return 2; } cout
  • *Shared Memory Examplefor (i = 0; i < PCOUNT; i++){ if ((pid = fork()) < 0) //fork failed { cout
  • *Shared Memory Example//The parent now needs to wait for the children (at least 1) to finishwait(0);cout
  • *Shared Memory Example W/ Sync rcotter@kc-sce-450p2 shmem]$ ./sharedmem_sShared memory is at: 0xb78ed0000 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 , 49 ,The sum of all values is 1225In parent before fork, memory is: 0xb78ed000We just created child 0 with pid 18745In child 0 memory is: 0xb78ed000We just created child 1 with pid 18746The sum for child 0 is 1225In child 2 memory is: 0xb78ed000The sum for child 2 is 1225We just created child 2 with pid 18747In child 1 memory is: 0xb78ed000The sum for child 1 is 1225:The sum for child 2 is 1225Child 0 just did 1000000 loopsChild 18745 just terminatedThe sum for child 1 is 1225:Child 1 just did 1000000 loopsChild 18746 just terminatedThe sum for child 2 is 1225:Child 2 just did 1000000 loopsChild 18747 just terminatedIn parent after fork, memory is : 0xb78ed000167 , 425 , 83 , 320 , 162 , -387 , -120 , -236 , 712 , 548 , 136 , -391 , -82 , 561 , -362 , -115 , 555 , 7 , -169 , -492 , -459 , 113 , -58 , 19 , 130 , -581 , 266 , 36 , 524 , -272 , -393 , -119 , -65 , 24 , 495 , 367 , -315 , -225 , -146 , 515 , -173 , 321 , -91 , -60 , 69 , -111 , 6 , 468 , -56 , -326 ,The sum of the array is now 1225

    Parent removing shared memory[rcotter@kc-sce-450p2 shmem]$

  • *Shared Memory Example W/O Sync[rcotter@kc-sce-450p2 shmem]$ ./sharedmemShared memory is at: 0xb77cb0000 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 , 49 ,The sum of all values is 1225In parent before fork, memory is: 0xb77cb000We just created child 0 with pid 18681We just created child 1 with pid 18682We just created child 2 with pid 18683In child 2 memory is: 0xb77cb000The sum for child 2 is 1225In child 0 memory is: 0xb77cb000The sum for child 0 is 1226In child 1 memory is: 0xb77cb000The sum for child 1 is 1222The sum for child 0 is 1221:Child 18681 just terminated.The sum for child 2 is 343The sum for child 1 is 343:Child 18683 just terminated.The sum for child 1 is 290:Child 18682 just terminated.In parent after fork, memory is : 0xb77cb000-204 , -443 , -85 , -339 , -178 , 390 , 101 , 232 , -717 , -548 , -116 , 384 , 102 , -533 , 365 , 123 , -537 , 52 , 217 , 497 , 485 , -101 , 100 , -4 , -99 , 619 , -216 , 6 , -500 , 316 , 432 , 152 , 98 , 29 , -433 , -333 , 368 , 289 , 187 , -461 , 232 , -257 , 152 , 130 , 4 , 175 , 30 , -386 , 121 , 392 ,The sum of the array is now 290Each process ran through 1000000 iterationsParent removing shared memory[rcotter@kc-sce-450p2 shmem]$

  • cs431-cotter*cs431-cotterSummarySeveral different sync mechanisms available in LinuxSignalWait MutexSemaphoreSeveral different IPC mechanismsPipesMessage queuesShared MemoryLinux specifications consistent with POSIX

    cs431-cotter

  • cs431-cotter*cs431-cotterQuestionsWhat is a signal handler table? Where is it located? How is it used by a process to handle signals sent to the process? How do you set up a program (process) to provide customized handling of a signal? (What code is needed to replace the default signal handler with our own signal handling routine? What function would a parent process use to capture the exit code of a terminated child process? If the parent process creates multiple child processes, how could it wait for one specific child process to terminate? If two processes want to pass information using annamed pipe, what must the relationship be between those processes (no relation required, parent and child, children of the same parent, processes in the same system, etc.) What functions (system calls) would be needed to create and initialize a semaphore in Linux? What functions are needed to actually use the semaphore in your program?

    cs431-cotter

    *cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cottercs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cotter*cs431-cottercs431-cottercs431-cottercs431-cottercs431-cotter