Solving the Producer Consumer Problem with PThreads

Similar documents
Introduction to PThreads and Basic Synchronization

The Dining Philosophers with Pthreads

Semaphores in Nachos. Dr. Douglas Niehaus Michael Jantz Dr. Prasad Kulkarni. EECS 678 Nachos Semaphores Lab 1

Chapter 6: Process Synchronization

CMSC421: Principles of Operating Systems

More Shared Memory Programming

Synchronising Threads

Synchronization. Dr. Yingwu Zhu

Introduction to parallel computing

CS 105, Spring 2015 Ring Buffer

CS 105, Spring 2007 Ring Buffer

Locks and semaphores. Johan Montelius KTH

High-level Synchronization

Semaphore. Originally called P() and V() wait (S) { while S <= 0 ; // no-op S--; } signal (S) { S++; }

W4118 Operating Systems. Instructor: Junfeng Yang

Paralleland Distributed Programming. Concurrency

TCSS 422: OPERATING SYSTEMS

Process Synchronization (Part I)

CS 31: Intro to Systems Misc. Threading. Kevin Webb Swarthmore College December 6, 2018

Locks and semaphores. Johan Montelius KTH

Semaphores. Jinkyu Jeong Computer Systems Laboratory Sungkyunkwan University

recap, what s the problem Locks and semaphores Total Store Order Peterson s algorithm Johan Montelius 0 0 a = 1 b = 1 read b read a

Threads need to synchronize their activities to effectively interact. This includes:

Interprocess Communication By: Kaushik Vaghani

Condition Variables CS 241. Prof. Brighten Godfrey. March 16, University of Illinois

Data Races and Deadlocks! (or The Dangers of Threading) CS449 Fall 2017

Dept. of CSE, York Univ. 1

ANSI/IEEE POSIX Standard Thread management

Synchronization I. Jo, Heeseung

Operating systems and concurrency (B08)

Synchroniza+on II COMS W4118

CHAPTER 6: PROCESS SYNCHRONIZATION

CSci 4061 Introduction to Operating Systems. Synchronization Basics: Locks

CS 333 Introduction to Operating Systems. Class 3 Threads & Concurrency. Jonathan Walpole Computer Science Portland State University

More Types of Synchronization 11/29/16

Synchronization. CS61, Lecture 18. Prof. Stephen Chong November 3, 2011

Synchronization Principles

Real Time Operating Systems and Middleware

Operating Systems. Designed and Presented by Dr. Ayman Elshenawy Elsefy

Reminder from last time

Condition Variables. Jinkyu Jeong Computer Systems Laboratory Sungkyunkwan University

PROCESS SYNCHRONIZATION

Operating Systems. Thread Synchronization Primitives. Thomas Ropars.

Process Synchronization

Concurrency. Chapter 5

Synchronization Primitives

Dealing with Issues for Interprocess Communication

EEE3052: Introduction to Operating Systems. Fall Project #3

Synchronization and Semaphores. Copyright : University of Illinois CS 241 Staff 1

Multithreading Programming II

Deadlock and Monitors. CS439: Principles of Computer Systems September 24, 2018

Recap: Thread. What is it? What does it need (thread private)? What for? How to implement? Independent flow of control. Stack

CS 333 Introduction to Operating Systems. Class 3 Threads & Concurrency. Jonathan Walpole Computer Science Portland State University

Chapter 6: Synchronization. Operating System Concepts 8 th Edition,

Systems Programming/ C and UNIX

What is the Race Condition? And what is its solution? What is a critical section? And what is the critical section problem?

Chapter 6: Synchronization. Chapter 6: Synchronization. 6.1 Background. Part Three - Process Coordination. Consumer. Producer. 6.

CS510 Advanced Topics in Concurrency. Jonathan Walpole

Chapter 6: Process Synchronization

CS444 1/28/05. Lab 03

Lecture 6. Process Synchronization

Lecture 5: Synchronization w/locks

Synchronization 1. Synchronization

CSE 451: Operating Systems Winter Lecture 7 Synchronization. Steve Gribble. Synchronization. Threads cooperate in multithreaded programs

Operating Systems CMPSCI 377 Spring Mark Corner University of Massachusetts Amherst

Lecture 4. Threads vs. Processes. fork() Threads. Pthreads. Threads in C. Thread Programming January 21, 2005

CS 167 Midterm Exam. Two Hours; Closed Book; Please Use a Black Pen March 23, 2017

Locks. Dongkun Shin, SKKU

Lecture 13 Condition Variables

Introduction to Nachos Scheduling

Module 6: Process Synchronization. Operating System Concepts with Java 8 th Edition

Chapter 6: Process Synchronization. Operating System Concepts 8 th Edition,

Pthreads (2) Dong-kun Shin Embedded Software Laboratory Sungkyunkwan University Embedded Software Lab.

CSE 153 Design of Operating Systems

Lecture 5 Threads and Pthreads II

IV. Process Synchronisation

Condition Variables. parent: begin child parent: end

Deadlock and Monitors. CS439: Principles of Computer Systems February 7, 2018

Operating Systems. Operating Systems Summer 2017 Sina Meraji U of T

CS370 Operating Systems

CSE 153 Design of Operating Systems

Chapter 5: Process Synchronization. Operating System Concepts 9 th Edition

Threads. Concurrency. What it is. Lecture Notes Week 2. Figure 1: Multi-Threading. Figure 2: Multi-Threading

Synchronization I. Jin-Soo Kim Computer Systems Laboratory Sungkyunkwan University

Condition Variables & Semaphores

Lecture Outline. CS 5523 Operating Systems: Concurrency and Synchronization. a = 0; b = 0; // Initial state Thread 1. Objectives.

CS533 Concepts of Operating Systems. Jonathan Walpole

Systèmes d Exploitation Avancés

Lesson 6: Process Synchronization

Condition Variables. Dongkun Shin, SKKU

Chapter 6: Process Synchronization. Module 6: Process Synchronization

So far, we've seen situations in which locking can improve reliability of access to critical sections.

Background. The Critical-Section Problem Synchronisation Hardware Inefficient Spinning Semaphores Semaphore Examples Scheduling.

Lab 12 - Concurrency 2

TCSS 422: OPERATING SYSTEMS

Project 3-2. Mutex & CV

CSE Traditional Operating Systems deal with typical system software designed to be:

Concept of a process

real time operating systems course

CSE 451: Operating Systems Winter Lecture 7 Synchronization. Hank Levy 412 Sieg Hall

Transcription:

Solving the Producer Consumer Problem with PThreads Michael Jantz Dr. Prasad Kulkarni Dr. Douglas Niehaus EECS 678 Pthreads: Producer-Consumer 1

Introduction This lab is an extension of last week's lab. This lab builds on the concepts learned from the PThreads Intro lab and Dining Philosophers lab. Go ahead and make and tag the starter code for this lab: tar xvzf eecs678-pthreads_pc-lab.tar.gz; cd pthreads_pc; make; ctags -R Helpful man pages for today: pthread_mutex_lock, pthread_mutex_unlock, pthread_cond_signal, pthread_cond_wait EECS 678 Pthreads: Producer-Consumer 2

The Producer - Consumer Problem The producer consumer problem is a common implementation pattern for cooperating processes or threads. Put simply, a producer produces information that is later consumed by a consumer. Traditionally, the problem is defined as follows: To allow the producer and consumer to run concurrently, the producer and consumer must share a common buffer. So that the consumer does not try to consume an item that has not yet been produced, the two processes must be synchronized. If the common data buffer is bounded, the consumer process must wait if the buffer is empty, and the producer process must wait if the buffer is full. There are many examples of this problem in real world applications. e.g., a build system may run multiple processes concurrently. The compiler process will produce assembly code to be read by the assembler process. If you have done socket programming, you used a socket as the data buffer between your client and server processes. Essentially, the operating system handled your synchronization issues. EECS 678 Pthreads: Producer-Consumer 3

An Instance of the PC Problem In producer_consumer.c, there is an instance of the PC problem. Producer threads and consumer threads are each created. They each share a bounded length FIFO queue. Producers place integers into the queue starting at 0 and ending at some predefined maximum (call it WORK_MAX). Producers announce each item they produce. Consumers remove one integer at a time from the queue, reporting each as it is consumed. Each consumers exits after WORK_MAX total removals by all consumers. EECS 678 Pthreads: Producer-Consumer 4

The Proposed Solution In order to solve the PC problem, the producer_consumer.c as it was distributed proposes the following solution : void *producer (void *q) { fifo = (queue *)q; while (1) { do_work(producer_cpu, PRODUCER_BLOCK); while (fifo->full && *total_produced!= WORK_MAX) { printf ("prod %d:\t FULL.\n", my_tid); } if (*total_produced == WORK_MAX) { break; } item_produced = (*total_produced)++; queueadd (fifo, item_produced); printf("prod %d:\t %d.\n", my_tid, item_produced); } return(null); } void *consumer (void *q) { fifo = (queue *)q; while (1) { while (fifo->empty && *total_consumed!= WORK_MAX) { printf ("con %d:\t EMPTY.\n", my_tid); } if (*total_consumed == WORK_MAX) { break; } queueremove (fifo, &item_consumed); (*total_consumed)++; do_work(consumer_cpu,consumer_cpu); printf ("con %d:\t %d.\n", my_tid, item_consumed); } return(null); } Essentially, when the queue is empty the consumer simply spins (as it has nothing to do), and when the queue is full the producer will spin (as it has nothing to do). EECS 678 Pthreads: Producer-Consumer 5

Problems With the Solution One of the problems with this solution is that it contains a race condition. Suppose the scheduler created the following interleaving: Producer Add last items to the queue. Set queue->empty = 0 i == WORK_MAX, producer exits. Consumer Remove an item from the queue. A check to see if the queue is empty shows that it is. Set queue->empty = 1. Set queue->full = 0 Start spinning. EECS 678 Pthreads: Producer-Consumer 6

Imposing Mutual Exclusion The basic problem with this solution is that the critical section of code, those accessing the shared total_produced, total_consumed, and queue variables, are not executed atomically For example, producer thread can preempt the consumer thread after the consumer has checked if the list is empty but before it has set the fifo->empty variable (and vice versa). Use pthread_mutex_lock( ) and pthread_mutex_unlock( ) to enforce mutual exclusion for the critical sections modifying the queue HINT: The mutex you should use has already been initialized and is called mutex in the queue structure. Also, your mutex calls should not surround the busy-wait loops yet. The modified solution protects the update of the queue itself but not the check of the queue->empty and queue->full flags, so it doesn't eliminate all problems of race conditions The solution also suffers from the problem of wasteful busy waiting. EECS 678 Pthreads: Producer-Consumer 7

Another Synchronization Problem Suppose the scheduler created the following interleaving after mutual exclusion is imposed on the queue manipulation Producer 2 will be adding an item to a queue that is full Producer 1 Producer 2 A check to see if the queue is full shows that it is not. pthread_mutex_lock( ) A check on total_produced Add an item to the queue. The queue is full now. pthread_mutex_unlock( ) A check to see if the queue is full shows that it is not. pthread_mutex_lock( ) A check on total_produced Add an item to the queue pthread_mutex_unlock( ) EECS 678 Pthreads: Producer-Consumer 8

Busy Waiting Problem Even if the thread is lucky enough to avoid this race condition, we are still wasting a lot of cycles by forcing each thread to spin when the conditions required for them to continue are not met. Many FULL and EMPTY messages can be printed Try 'bash> grep EMPTY narrative1.raw wc' There were 43,000 in our example run You can comment out the busy-wait printfs to see behavior differently Consider how many wasted cycles are executed. And this is with a blocking print statement! Also there is still a race wrt the empty and full flags Condition variables were invented to help with these kinds of situations among others EECS 678 Pthreads: Producer-Consumer 9

Signal and Wait The pthread_mutex_lock( ) and pthread_mutex_unlock( ) library calls are implemented using more primitive methods provided by the operating system (via the futex system call). A process calling wait(fred) will attempt to acquire the mutex fred if it is available. If it is not available, the calling process will insert itself into a list of waiters associated with the mutex fred, and will block (i.e. remove itself from the scheduler's list of processes ready to run). This is essentially the operation of pthread_mutex_lock. A process calling signal(fred) will wakeup a process in fred's waiters list if one is present (i.e. change its blocked state to ready and place it on the scheduler's ready list). This is essentially the operation of pthread_mutex_unlock. EECS 678 Pthreads: Producer-Consumer 10

Condition Variables The question becomes, can we use block and wakeup to implement more precise and efficient synchronization? It turns out we can. And the POSIX standard provides a component called a condition variable that makes using these primitives convenient and intuitive. A condition variable has its own list of waiters associated with it. When a program reaches a point where it should wait for some condition to be true, it blocks and inserts itself into the condition variable's waiters list using pthread_cond_wait( ) When the condition is met, any process with access to the condition variable can wakeup a process on the condition variable's waiters list, pthread_cond_signal( ), or all waiters, pthread_cond_broadcast( ) EECS 678 Pthreads: Producer-Consumer 11

Library Calls pthread_cond_wait( ) forces a thread to block until a certain condition has been signaled: int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); This call atomically unlocks the associated mutex and waits for the condition variable cond to be signaled. It requires that the associated mutex must be locked by the calling thread on entrance to this call. Before returning to the calling thread, pthread_cond_wait re-acquires the associated mutex. pthread_cond_signal() signals a particular condition variable: int pthread_cond_signal(pthread_cond_t *cond); This call restarts one of the threads that are waiting on the condition variable cond. If no threads are waiting on cond nothing happens. If several threads are waiting on cond, exactly one is restarted, but it is not specified which. Use pthread_cond_broadcast(pthread_cond_t *cond) to wake all threads waiting on a particular condition variable Note: a mutex is used to ensure operations on the condition variable are atomic EECS 678 Pthreads: Producer-Consumer 12

Modifying producer_consumer.c Modify producer_consumer.c to make use of the condition variable library calls described above to handle one producer and one consumer When you are through, the producer and consumer should not spin until the condition they are waiting on is met, but should actually block their own execution. They should be signaled to wake up when that condition is satisfied. As a hint, the starter code has initialized all the mutexes and condition variables you should need. You can use the same mutex as before to associate with the condition variables. The condition variables created and initialized are fairly obvious: fifo->notfull, and fifo->notempty. EECS 678 Pthreads: Producer-Consumer 13

Output When you are through, the output of the printf statements will provide information by which you can verify the semantics specified on the previous slide are present Makefile targets: test1, test2, test3 and test4 run with various numbers of producers and consumers NarrativeX.raw gives the raw output of testx NarrativeX.sorted gives output for each thread separately Raw output shows how execution of threads are interleaved Sorted output shows the sequence of actions by each thread The amount of working and blocking time associated with each item can affect how threads behave, and thus how their execution is interleaved Change the settings and see how behavior changes, if it does Also, run a given test multiple times with the same setting and look for differences in behavior due to random chance and changing system conditions EECS 678 Pthreads: Producer-Consumer 14

Lab Assignment Your final task for this lab is to experiment with producer_consumer using different numbers of threads and different work settings If you have modified the producer and consumer routines to use the mutex and condition variables correctly, the program should work correctly for arbitrary numbers of threads How will you ensure the producers (consumers) produce (consume) the correct number of items? Consider how the integer pointer to the number consumed and the number produced is used. EECS 678 Pthreads: Producer-Consumer 15

Testing producer_consumer takes as its arguments the number of producer and consumer threads it will use. Test your program for different combinations of producers and consumers: several producers and 1 consumer, 1 producer and several consumers, several producers and consumers. The testx makefile targets are a guide, but try other things as well You will have to create your own raw and sorted files for new tests Examine the raw and sorted output for a given test and see what you can deduce about behavior EECS 678 Pthreads: Producer-Consumer 16

Conclusions Producer-Consumer is an extremely simple canonical problem which arises in a wide range of situations Yet, as simple as it is, there are a number of interesting features and a wide range of behavior One important part of this assignment is to look for small inconsistencies or other features of a behavior narrative that indicate unexpected scenarios Another important aspect is to note how variable the behavior of different runs under the same settings can be Concurrency is subject to a lot of random variation EECS 678 Pthreads: Producer-Consumer 17