0% found this document useful (0 votes)
249 views6 pages

Operating Systems Lab Assignment 6: Synchronization Using Semaphores

The document describes a lab assignment on using semaphores for synchronization in C programs. It provides guidelines on using semaphores to control access to shared resources between threads. Specifically, it describes implementing a producer-consumer problem where a producer thread adds items to a shared buffer and a consumer thread removes items from the buffer. The student is tasked with writing a C program that uses semaphores to synchronize a producer and consumer thread to safely produce and consume the alphabet letters between them.

Uploaded by

api-526395450
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
249 views6 pages

Operating Systems Lab Assignment 6: Synchronization Using Semaphores

The document describes a lab assignment on using semaphores for synchronization in C programs. It provides guidelines on using semaphores to control access to shared resources between threads. Specifically, it describes implementing a producer-consumer problem where a producer thread adds items to a shared buffer and a consumer thread removes items from the buffer. The student is tasked with writing a C program that uses semaphores to synchronize a producer and consumer thread to safely produce and consume the alphabet letters between them.

Uploaded by

api-526395450
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 6

Operating Systems

Lab assignment 6: Synchronization using semaphores

Objectives
1. To use semaphores for synchronization
2. To develop a C program to solve the producer – consumer problem

Guidelines
You have learned in class that threads run concurrently and when they read/write to a shared memory, the
program behavior is undefined. This is due to the fact the CPU scheduler switches rapidly between threads to
provide concurrent execution. One thread may only partially complete execution before another thread is
scheduled. Therefore, a thread may be interrupted at any point in its instruction stream, and the CPU may be
assigned to execute instructions of another thread, and so the thread schedule is non-deterministic and the
resulting output is non-reproducible. To control the non-deterministic and non-reproducible behavior of multi-
threaded programs, synchronization is required.

Each thread has a segment of code that involves data sharing with one or more threads. This code segment is
referred to as a critical section. Synchronization imposes a rule that when one thread is executing in its critical
section, no other thread is allowed to execute in its critical section. Each thread must request permission to enter
its critical section, formally defined as the entry section. When a thread completes execution in the critical section,
it leaves through an exit section to the remaining code of the program. The general structure of synchronization is
therefore defined as follows:
do {
entry section
critical section
exit section
remainder section
} while (1);
A variety of synchronization tools exit. In this lab, semaphores are used for demonstration. A semaphore
is considered a generalized lock and it supports two operations:
- P(): an atomic operation that waits for semaphore to become positive, then decrements it by 1. This
operation is referred to as wait() operation
- V(): an atomic operation that increments the semaphore by 1, waking up a waiting P, if any. This
operation is referred to as signal() operation.

P() stands for “proberen” (to test) and V() stands for “verhogen” (to increment) in Dutch. Linux provides a high-
level APIs for semaphores in the <semaphore.h> library:
sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);

Lab assignment 6 1/3


int sem_destroy(sem_t *sem);
Note: MacOs does not support sem_init and sem_destroy (unnamed semaphores). If you are using MacOS, use
a named semaphore with sem_open, and sem_unlink as follows:
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
int sem_unlink(const char *name);

C Program with semaphores


In lab 5, theadHello.c program was demonstrated. In this lab, the program is implemented with semaphores.
Demonstrate each of the following steps to the TA to get a grade on this part of the lab assignment.

Step 1. Download the threadSync.c program from iLearn, then compile and run several times. The comment at
the top of program explains how to compile and run the program.

Explain what happens when you run the threadSync.c program?

Producer – Consumer as a classical problem of synchronization


Step 2. Write a program* that solves the producer - consumer problem. You may use the following pseudo code
for implementation.

*program to write: produce -consumer problem to produce and consume the alphabet.

//Shared data: semaphore full, empty, mutex;


//pool of n buffers, each can hold one item
//mutex provides mutual exclusion to the buffer pool
//empty and full count the number of empty and full buffers
//Initially: full = 0, empty = n, mutex = 1

//Producer thread
do {

produce next item

wait(empty);
wait(mutex);

add the item to buffer

signal(mutex);
signal(full);
} while (1);

//Consumer thread
do {
wait(full)
wait(mutex);

remove next item from buffer

signal(mutex);
signal(empty);

consume the item

Lab assignment 6 2/3


} while (1);

Requirements to complete the lab


1. Show the TA correct execution of the C programs.
2. Submit your answers to questions, observations, and notes as .txt file and upload to iLearn
3. Submit the source code for your programs as .c file(s) and upload to iLearn

Be sure to retain copies of your .c and .txt files. You will want these for study purposes and to resolve any grading
questions (should they arise)

Please start each program/ text with a descriptive block that includes minimally the following information:

# Name: <your name>


# Date: <date> (the day you have lab)
# Title: Lab6 – task
# Description: This program computes … <you should
# complete an appropriate description here.>

Lab assignment 6 3/3


1 // Name: <Thomas Wooten>
2 // Date: <April 13,2021>
3 // Title: Lab 6
4 // Description: threadSync.c - simple multi-threaded program with sychronization.
5
6 #include <stdio.h>
7 #include <unistd.h>
8 #include <pthread.h>
9 #include <semaphore.h>
10
11 #define NTHREADS 10
12 pthread_t threads[NTHREADS];
13 sem_t mutex;
14
15 void* go(void* arg) {
16 sem_wait(&mutex);
17 printf("Thread %lu Entered Critical Section..\n", (size_t)arg);
18 sleep(1);
19 sem_post(&mutex);
20 return (NULL);
21 }
22
23 int main() {
24 sem_init(&mutex,0,1);
25 static int i;
26
27 for (i = 0; i < NTHREADS; i++)
28 pthread_create(&threads[i], NULL, go, (void *)(size_t)i);
29 for (i = 0; i < NTHREADS; i++) {
30 pthread_join(threads[i],NULL);
31 printf("Thread %d returned \n", i);
32 }
33 printf("Main thread done.\n");
34 sem_destroy(&mutex);
35 return 0;
36 }
37
1 // Name: <Thomas Wooten>
2 // Date: <April 13,2021>
3 // Title: Lab 6
4 // Description: produce-consumer problem: program to produce and consume the alphabet.
5
6 #include <stdio.h>
7 #include <unistd.h>
8 #include <pthread.h>
9 #include <semaphore.h>
10
11 #define BUFFER_SIZE 4
12 #define SIZE_OF_ALPHABET 26
13
14 //data type to store information about buffer
15 typedef struct{
16 char value[BUFFER_SIZE];
17 int In, Out;
18 } buffer_t;
19
20 // producer function
21 void* producer(void* arg);
22 // consumer function
23 void* consumer(void* arg);
24
25 // create instances
26 pthread_t threadProducer;
27 pthread_t threadConsumer;
28 pthread_mutex_t mutex;
29 sem_t empty, full;
30 buffer_t buffer;
31
32 // main functuon
33 int main(){
34
35 pthread_mutex_init(&mutex, NULL); // intilize mutex
36 sem_init(&empty,0,BUFFER_SIZE); // intilize empty
37 sem_init(&full,0,0); // intilize full
38
39 pthread_create(&threadProducer, NULL, (void *)producer, NULL); //create threadP
40 pthread_create(&threadConsumer, NULL, (void *)consumer, NULL); //create threadC
41
42 // wait for threads to complete
43 pthread_join(threadProducer, NULL);
44 pthread_join(threadConsumer, NULL);
45
46 //deallocate memory
47 pthread_mutex_destroy(&mutex);
48 sem_destroy(&empty);
49 sem_destroy(&full);
50
51 return 0;
52 }
53
54 // producer function
55 void* producer(void* arg){
56
57
58 for ( int i = 0; i < SIZE_OF_ALPHABET; i++){
59
60 sem_wait(&empty);
61 pthread_mutex_lock(&mutex);
62
63 char alpha = 'A' + (i % SIZE_OF_ALPHABET);
64 buffer.value[buffer.In] = alpha;
65 printf("Producer --> %c\n", alpha);
66 buffer.In = (buffer.In + 1) % BUFFER_SIZE;
67
68 pthread_mutex_unlock(&mutex);
69 sem_post(&full);
70 }
71
72 return (NULL);
73 }
74
75 // consumer function
76 void* consumer(void* arg){
77
78 for ( int i = 0; i < SIZE_OF_ALPHABET ; i++){
79
80 sem_wait(&full);
81 pthread_mutex_lock(&mutex);
82
83 printf("Consumer <-- %c\n", buffer.value[buffer.Out]);
84 buffer.Out = (buffer.Out + 1) % BUFFER_SIZE;
85
86 pthread_mutex_unlock(&mutex);
87 sem_post(&empty);
88 }
89
90 return (NULL);
91 }
92

You might also like