NAME
pthread_mutex_destroy, pthread_mutex_init - destroy and initialize a
mutex
SYNOPSIS
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
The pthread_mutex_init() function initialises the mutex referenced by mutex with attributes specified by attr. If attr is NULL, the default mutex attributes are used; the effect is the same as passing the address of a default mutex attributes object. Upon successful initialisation, the state of the mutex becomes initialised and unlocked.
Attempting to initialise an already initialised mutex results in undefined behaviour.
In cases where default mutex attributes are appropriate, the macro PTHREAD_MUTEX_INITIALIZER can be used to initialise mutexes that are statically allocated.
#include <pthread.h>
pthread_mutex_t mp = PTHREAD_MUTEX_INITIALIZER;
pthread_mutexattr_t mattr;
int ret;
/* initialize a mutex to its default value */
ret = pthread_mutex_init(&mp, NULL);
NAME
pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock - lock
and unlock a mutex
SYNOPSIS
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_mutex_init()
Initialize mutex
Synopsis:
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_init(
pthread_mutex_t* mutex,
const pthread_mutexattr_t* attr );
Arguments:
mutex
A pointer to the pthread_mutex_t object that you want to initialize.
attr
NULL, or a pointer to a pthread_mutexattr_t object that specifies the attributes that you want to use for the mutex. For more information, see pthread_mutexattr_init().
Library:
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
Description:
The pthread_mutex_init() function initializes the given mutex object, using the attributes specified by the mutex attributes object attr. If attr is NULL, then the mutex is initialized with the default attributes (see pthread_mutexattr_init()). After initialization, the mutex is in an unlocked state.
You can initialize a statically allocated mutex with the default attributes by assigning to it the macro PTHREAD_MUTEX_INITIALIZER or PTHREAD_RMUTEX_INITIALIZER (for recursive mutexes).
default attributes PTHREAD_MUTEX_INITIALIZER or PTHREAD_RMUTEX_INITIALIZER (for recursive mutexes).
pthread_mutexattr_init()
Initialize a mutex attribute object
Synopsis:
#include <pthread.h>
int pthread_mutexattr_init( pthread_mutexattr_t* attr );
Arguments:
attr
A pointer to the pthread_mutexattr_t object that you want to initialize.
Library:
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
Description:
The pthread_mutexattr_init() function initializes the attributes in the mutex attribute object attr to their default values. After initializing a mutex attribute object, you can use it to initialize one or more mutexes by calling pthread_mutex_init().
The mutex attributes and their default values are:
__protocol
PTHREAD_PRIO_INHERIT--when a thread is blocking higher-priority threads by locking one or more mutexes with this attribute, the thread's priority is raised to that of the highest priority thread waiting on the PTHREAD_PRIO_INHERIT mutex.
__recursive
PTHREAD_RECURSIVE_DISABLE--threads can't recursively lock a mutex; any thread that tries to lock an already locked mutex becomes blocked.
Mutex Example
/* in /cs/cs3013/public/example/mutexthr.c */
#include <stdio.h>
#include <pthread.h>
/* cc -o mutexthr mutexthr.c -lpthread */
pthread_mutex_t mutex; /* mutex id */
main()
{
pthread_t idA, idB; /* ids of threads */
void *MyThread(void *);
if (pthread_mutex_init(&mutex, NULL) < 0) {
perror("pthread_mutex_init");
exit(1);
}
if (pthread_create(&idA, NULL, MyThread, (void *)"A") != 0) {
perror("pthread_create");
exit(1);
}
if (pthread_create(&idB, NULL, MyThread, (void *)"B") != 0) {
perror("pthread_create");
exit(1);
}
(void)pthread_join(idA, NULL);
(void)pthread_join(idB, NULL);
(void)pthread_mutex_destroy(&mutex);
}
int x = 0; /* global shared variable */
void *MyThread(void *arg)
{
char *sbName;
sbName = (char *)arg;
IncrementX();
printf("X = %d in Thread %s\n", x, sbName);
}
IncrementX()
{
int Temp; /* local variable */
BeginRegion(); /* enter critical region */
Temp = x;
Temp = Temp + 1;
x = Temp;
EndRegion(); /* exit critical region */
}
BeginRegion()
{
pthread_mutex_lock(&mutex);
}
EndRegion()
{
pthread_mutex_unlock(&mutex);
}
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int count = 0;
void* function1( void* arg )
{
int tmp = 0;
while( 1 ) {
pthread_mutex_lock( &mutex );
tmp = count++;
pthread_mutex_unlock( &mutex );
printf( "Count is %d\n", tmp );
/* snooze for 1 second */
sleep( 1 );
}
return 0;
}
void* function2( void* arg )
{
int tmp = 0;
while( 1 ) {
pthread_mutex_lock( &mutex );
tmp = count--;
pthread_mutex_unlock( &mutex );
printf( "** Count is %d\n", tmp );
/* snooze for 2 seconds */
sleep( 2 );
}
return 0;
}
int main( void )
{
pthread_create( NULL, NULL, &function1, NULL );
pthread_create( NULL, NULL, &function2, NULL );
/* Let the threads run for 60 seconds. */
sleep( 60 );
return 0;
}
Synchronization Example
/* in /cs/cs3013/public/example/pcthreads.c */
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
/* cc -o pcthreads pcthreads.c -lpthread -lrt */
sem_t produced, consumed; /* semaphores */
int n;
main()
{
pthread_t idprod, idcons; /* ids of threads */
void *produce(void *);
void *consume(void *);
int loopcnt = 5;
n = 0;
if (sem_init(&consumed, 0, 0) < 0) {
perror("sem_init");
exit(1);
}
if (sem_init(&produced, 0, 1) < 0) {
perror("sem_init");
exit(1);
}
if (pthread_create(&idprod, NULL, produce, (void *)loopcnt) != 0) {
perror("pthread_create");
exit(1);
}
if (pthread_create(&idcons, NULL, consume, (void *)loopcnt) != 0) {
perror("pthread_create");
exit(1);
}
(void)pthread_join(idprod, NULL);
(void)pthread_join(idcons, NULL);
(void)sem_destroy(&produced);
(void)sem_destroy(&consumed);
}
void *produce(void *arg)
{
int i, loopcnt;
loopcnt = (int)arg;
for (i=0; i<loopcnt; i++) {
sem_wait(&consumed);
n++; /* increment n by 1 */
sem_post(&produced);
}
}
void *consume(void *arg)
{
int i, loopcnt;
loopcnt = (int)arg;
for (i=0; i<loopcnt; i++) {
sem_wait(&produced);
printf("n is %d\n", n); /* print value of n */
sem_post(&consumed);
}
}
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#define NITER 1000000
int count = 0;
void * ThreadAdd(void * a)
{
int i, tmp;
for(i = 0; i < NITER; i++)
{
tmp = count; /* copy the global count locally */
tmp = tmp+1; /* increment the local copy */
count = tmp; /* store the local value into the global count */
}
}
int main(int argc, char * argv[])
{
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, ThreadAdd, NULL);
pthread_create(&tid2, NULL, ThreadAdd, NULL);
pthread_join(tid1, NULL))/* wait for the thread 1 to finish */
pthread_join(tid2, NULL); /* wait for the thread 2 to finish */
if (count < 2 * NITER)
printf("\n BOOM! count is [%d], should be %d\n", count, 2*NITER);
else
printf("\n OK! count is [%d]\n", count);
pthread_exit(NULL);
}
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
לבדוק על המחשב!!!!!
יצרן צרכן של איבר אחד בלבד
לסמפורים
/* cc -o pcthreads pcthreads.c -lpthread -lrt */
sem_t produced, consumed; /* semaphores */
int n;
main()
{
pthread_t idprod, idcons; /* ids of threads */
void *produce(void *);
void *consume(void *);
int loopcnt = 5;
n = 0;
sem_init(&consumed, 0, 0) < 0)
sem_init(&produced, 0, 1) < 0)
pthread_create(&idprod, NULL, produce, (void *)loopcnt)
pthread_create(&idcons, NULL, consume, (void *)loopcnt)
(void)pthread_join(idprod, NULL);
(void)pthread_join(idcons, NULL);
(void)sem_destroy(&produced);
(void)sem_destroy(&consumed);
}
void *produce(void *arg)
{
int i, loopcnt;
loopcnt = (int)arg;
for (i=0; i<loopcnt; i++) {
sem_wait(&consumed);
n++; /* increment n by 1 */
sem_post(&produced);
}
}
void *consume(void *arg)
{
int i, loopcnt;
loopcnt = (int)arg;
for (i=0; i<loopcnt; i++) {
sem_wait(&produced);
printf("n is %d\n", n); /* print value of n */
sem_post(&consumed);
}
}
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include </usr/include/semaphore.h>
לסמפורים
#define BUFF_SIZE 5/* total number of slots */
#define NP 3/* total number of producers */
#define NC 3/* total number of consumers */
#define NITERS 4/* number of items produced/consumed */
typedef struct {
int buf[BUFF_SIZE]; /* shared var */
int in; /* buf[in%BUFF_SIZE] is the first empty slot */
int out; /* buf[out%BUFF_SIZE] is the first full slot */
sem_t full; /* keep track of the number of full spots */
sem_t empty; /* keep track of the number of empty spots */
sem_t mutex; /* enforce mutual exclusion to shared data */
} sbuf_t;
sbuf_t shared;
void *Producer(void *arg)
{
int i, item, index;
index = (int)arg;
for (i=0; i < NITERS; i++) {
/* Produce item */
item = i;
printf("[P%d] Producing %d ...\n", index, item); fflush(stdout);
/* Write item to buf */
/* If there are no empty slots, wait */
sem_wait(&shared.empty);
/* If another thread uses the buffer, wait */
sem_wait(&shared.mutex);
shared.buf[shared.in] = item;
shared.in = (shared.in+1)%BUFF_SIZE;
/* Release the buffer */
sem_post(&shared.mutex);
/* Increment the number of full slots */
sem_post(&shared.full);
/* Interleave producer and consumer execution */
if (i % 2 == 1) sleep(1);
}
return NULL;
}
void *Consumer(void *arg)
{
/* Fill in the code here */
}
int main()
{
pthread_t idP, idC;
int index;
sem_init(&shared.full, 0, 0);
sem_init(&shared.empty, 0, BUFF_SIZE);
/* Insert code here to initialize mutex*/
for (index = 0; index < NP; index++)
{
/* Create a new producer */
pthread_create(&idP, NULL, Producer, (void*)index);
}
/* Insert code here to create NC consumers */
pthread_exit(NULL);
}
/* Includes */
#include<unistd.h> /* Symbolic Constants */
#include<sys/types.h> /* Primitive System Data Types */
#include<errno.h> /* Errors */
#include<stdio.h> /* Input/Output */
#include<stdlib.h> /* General Utilities */
#include<pthread.h> /* POSIX Threads */
#include<string.h> /* String handling */
#include<semaphore.h> /* Semaphore */
/* prototype for thread routine */
voidhandler(void*ptr );
/* global vars */
/* semaphores are declared global so they can be accessed
in main() and in thread routine,
here, the semaphore is used as a mutex */
sem_t mutex;
int counter;/* shared variable */
intmain()
{
int i[2];
pthread_t thread_a;
pthread_t thread_b;
i[0]=0;/* argument to threads */
i[1]=1;
sem_init(&mutex,0,1); /* initialize mutex to 1 - binary semaphore */
/* second param = 0 - semaphore is local */
/* Note: you can check if thread has been successfully created by checking return value ofpthread_create */
pthread_create(&thread_a, NULL,(void*)handler,(void*)i[0]);
pthread_create(&thread_b, NULL,(void*)handler,(void*)i[1]);
pthread_join(thread_a, NULL);
pthread_join(thread_b, NULL);
sem_destroy(&mutex);/* destroy semaphore */
/* exit */
exit(0);
}/* main() */
voidhandler(void*ptr )
{
int x;
x =*((int*) ptr);
printf("Thread %d: Waiting to enter critical region...\n", x);
sem_wait(&mutex); /* down semaphore */
/* START CRITICAL REGION */
printf("Thread %d: Now in critical region...\n", x);
printf("Thread %d: Counter Value: %d\n", x, counter);
printf("Thread %d: Incrementing Counter...\n", x);
counter++;
printf("Thread %d: New Counter Value: %d\n", x, counter);
printf("Thread %d: Exiting critical region...\n", x);
/* END CRITICAL REGION */
sem_post(&mutex); /* up semaphore */
pthread_exit(0);/* exit thread */
}
allow the programmer to "lock" an object so that only one thread can access it.
#include <pthread.h>
intpthread_mutex_init(pthread_mutex_t *mutex, const pthread_muteattr_t &mutexattr)
int pthread_mutex_lock(pthread_mutex_t *mutex) ;
int pthread_mutex_unlock(pthread_mutex_t *mutex) ;
int pthread_mutex_destory(pthread_mutex_t *mutex) ;
mutexattr: by default is "fast" ¿ִֹµ¼ײְֲֻֻר »עױַֺ¶א´־¼׃ֻר־ֺּג
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
void *thread_function(void *arg);
pthread_mutex_t work_mutex; /* protects both work_area and time_to_exit */
#define WORK_SIZE 1024
char work_area[WORK_SIZE];
int time_to_exit = 0;
int main() {
int res;
pthread_t a_thread;
void *thread_result;
res = pthread_mutex_init(&work_mutex, NULL);
if (res != 0) {
perror("Mutex initialization failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&a_thread, NULL, thread_function, NULL);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
pthread_mutex_lock(&work_mutex);
printf("Input some text. Enter 'end' to finish\n");
while(!time_to_exit) {
fgets(work_area, WORK_SIZE, stdin);
pthread_mutex_unlock(&work_mutex);
while(1) {
pthread_mutex_lock(&work_mutex);
if (work_area[0] != '\0') {
pthread_mutex_unlock(&work_mutex);
sleep(1);
}
else {
break;
}
}
}
pthread_mutex_unlock(&work_mutex);
printf("\nWaiting for thread to finish...\n");
res = pthread_join(a_thread, &thread_result);
if (res != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joined\n");
pthread_mutex_destroy(&work_mutex);
exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
sleep(1);
pthread_mutex_lock(&work_mutex);
while(strncmp("end", work_area, 3) != 0) {
printf("You input %d characters\n", strlen(work_area) -1);
work_area[0] = '\0';
pthread_mutex_unlock(&work_mutex);
sleep(1);
pthread_mutex_lock(&work_mutex);
while (work_area[0] == '\0' ) {
pthread_mutex_unlock(&work_mutex);
sleep(1);
pthread_mutex_lock(&work_mutex);
}
}
time_to_exit = 1;
work_area[0] = '\0';
pthread_mutex_unlock(&work_mutex);
pthread_exit(0);
}
Example 1:
Two threads displaying two strings “Hello” and “How are you?” independent of each other.
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
void * thread1()
{
while(1){
printf("Hello!!\n");
}
}
void * thread2()
{
while(1){
printf("How are you?\n");
}
}
int main()
{
int status;
pthread_t tid1,tid2;
pthread_create(&tid1,NULL,thread1,NULL);
pthread_create(&tid2,NULL,thread2,NULL);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}
Now compile this program (Note the -l option is to load the pthread library)
$gcc thread.c -lpthread
On running, you can see many interleaved “Hello!!” and “How are you?” messages
Example 2
This example involves a reader and a writer thread. The reader thread reads a string from the user and writer thread displays it. This program uses semaphore so as to achieve synchronization
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
char n[1024];
sem_t len;
void * read1()
{
while(1){
printf("Enter a string");
scanf("%s",n);
sem_post(&len);
}
}
void * write1()
{
while(1){
sem_wait(&len);
printf("The string entered is :");
printf("==== %s\n",n);
}
}
int main()
{
int status;
pthread_t tr, tw;
pthread_create(&tr,NULL,read1,NULL);
pthread_create(&tw,NULL,write1,NULL);
pthread_join(tr,NULL);
pthread_join(tw,NULL);
return 0;
}
On running, in most cases we may be able to achieve a serial read and write( Thread1reads a string and Thread2 displays the same string). But suppose we insert a sleep function() in write1 like
void * write1()
{
while(1){
sleep(5);
sem_wait(&len);
printf("The string entered is :");
printf("==== %s\n",n);
}
}
The thread 1 may read one more string and thread2 displays the last read string. That is no serial read and write is achieved.
So we may need to use the condition variables to achieve serial read and write.
Example 3
This example involves a reader and a writer thread. The reader thread reads a string from the user and writer thread displays it. This program uses condition variables to achieve synchronization and achieve serial programming.
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
char n[1024];
pthread_mutex_t lock= PTHREAD_MUTEX_INITIALIZER;
int string_read=FALSE;
pthread_cond_t cond;
void * read1()
{
while(1){
while(string_read);
pthread_mutex_lock(&lock);
printf("Enter a string: ");
scanf("%s",n);
string_read=TRUE;
pthread_mutex_unlock(&lock);
pthread_cond_signal(&cond);
}
}
void * write1()
{
while(1){
pthread_mutex_lock(&lock);
while(!string_read)
pthread_cond_wait(&cond,&lock);
printf("The string entered is %s\n",n);
string_read=FALSE;
pthread_mutex_unlock(&lock);
}
}
int main()
{
int status;
pthread_t tr, tw;
pthread_create(&tr,NULL,read1,NULL);
pthread_create(&tw,NULL,write1,NULL);
pthread_join(tr,NULL);
pthread_join(tw,NULL);
return 0;
}
Use of SIGINT (Cntr+C) is used to quit the program.
#include < stdio.h >
#include < pthread.h >
#include < semaphore.h >
#include < signal.h >
sem_t semname;
int qval=1;
void *func1(void *arg) {
while(qval) {
sem_wait(&semname);
printf("Thread one prints # %d\n",(*(int *)(arg))++);
sem_post(&semname);
sleep(1);
}
}
void *func2(void *arg) {
while(qval) {
sem_wait(&semname);
printf("Thread two prints # %d\n",(*(int *)(arg))++);
sem_post(&semname);
sleep(1);
}
}
void quit() {
qval=0;
}
main() {
int i=0;
signal(SIGINT,quit); //ctrl+c
sem_init(&semname,0,1);
pthread_t thread1,thread2;
pthread_create(&thread1,NULL,func1,&i);
pthread_create(&thread2,NULL,func2,&i);
pthread_join(thread1,&i);
pthread_join(thread2,&i);
printf("\nQuiting...\n");
return 0;
}
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NITER 1000000000
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
long count = 0, count1 = 0;
void * ThreadAdd(void * a) {
long i, tmp;
for(i = 0; i < NITER; i++)
{
count++
}
}
int main(int argc, char * argv[]) {
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, ThreadAdd, NULL);
pthread_create(&tid2, NULL, ThreadAdd, NULL);
pthread_join(tid1, NULL);/* wait for the thread 1 to finish */
pthread_join(tid2, NULL);/* wait for the thread 2 to finish */
if (count < 2 * NITER)
printf("\n BOOM! count is [%ld], should be %ld\n", count, 2*NITER);
else
printf("\n OK! count is [%ld]\n", count);
pthread_exit(NULL);
}
BOOM! count is [1971985225], should be 2000000000
/* a simple producer/consumer using semaphores and threads
usage on Solaris:
gcc thisfile.c -lpthread -lposix4
a.out numIters
*/
#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#define SHARED 1
void *Producer(void *); /* the two threads */
void *Consumer(void *);
sem_t empty, full; /* the global semaphores */
int data; /* shared buffer */
int numIters;
/* main() -- read command line and create threads, then
print result when the threads have quit */
int main(int argc, char *argv[]) {
/* thread ids and attributes */
pthread_t pid, cid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
numIters = atoi(argv[1]);
sem_init(&empty, SHARED, 1); /* sem empty = 1 */
sem_init(&full, SHARED, 0); /* sem full = 0 */
printf("main started\n");
pthread_create(&pid, &attr, Producer, NULL);
pthread_create(&cid, &attr, Consumer, NULL);
pthread_join(pid, NULL);
pthread_join(cid, NULL);
printf("main done\n");
}
/* deposit 1, ..., numIters into the data buffer */
void *Producer(void *arg) {
int produced;
printf("Producer created\n");
for (produced = 0; produced < numIters; produced++) {
sem_wait(&empty);
data = produced;
sem_post(&full);
}
}
/* fetch numIters items from the buffer and sum them */
void *Consumer(void *arg) {
int total = 0, consumed;
printf("Consumer created\n");
for (consumed = 0; consumed < numIters; consumed++) {
sem_wait(&full);
total = total+data;
sem_post(&empty);
}
printf("for %d iterations, the total is %d\n", numIters, total);
}
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#define NITER 1000000000
sem_t mutex;
long count = 0, count1 = 0;
void * ThreadAdd(void * a) {
for(long i = 0; i < NITER; i++)
{
sem_wait(&mutex);
count++;
sem_post(&mutex);}
for(i = 0; i < NITER; i++)count++;
}
int main(int argc, char * argv[]) {
pthread_t tid1, tid2;
sem_init(&mutex,0,1);
pthread_create(&tid1, NULL, ThreadAdd, NULL);
pthread_create(&tid2, NULL, ThreadAdd, NULL);
pthread_join(tid1, NULL);/* wait for the thread 1 to finish */
pthread_join(tid2, NULL);/* wait for the thread 2 to finish */
if (count < 2 * NITER)
printf("\n BOOM! count is [%ld], should be %ld\n", count, 2*NITER);
else
printf("\n OK! count is [%ld]\n", count);
if (count < 2 * NITER)
printf("\n BOOM! count1 is [%ld], should be %ld\n", count1, 2*NITER);
else
printf("\n OK! count1 is [%ld]\n", count1);
sem_destroy(&mutex);
pthread_exit(NULL);
}
OK! count is [2000000000]
BOOM! count is [16372624], should be 2000000000
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#define BUFF_SIZE 100/* total number of slots */
#define NP 2/* total number of producers - 1*/
#define NC 5/* total number of consumers - 1 */
#define NITERS 4/* number of items produced/consumed */
typedef struct {
int buf[BUFF_SIZE]; /* shared var */
int in; /* buf[in%BUFF_SIZE] is the first empty slot */
int out; /* buf[out%BUFF_SIZE] is the first full slot */
sem_t full; /* keep track of the number of full spots */
sem_t empty; /* keep track of the number of empty spots */
sem_t mutex; /* enforce mutual exclusion to shared data */
} sbuf_t;
sbuf_t shared;
/* function prototypes */
void *Producer(void *arg);
void *Consumer(void *arg);
/* increments and decrements */
int produced, consumed;
int main()
{
/* producer/consumer threads */
pthread_t idP, idC;
/* loop control */
int index;
/* temp variables to comp the consumes and produces per hour */
int temp1, temp2;
int ratio = temp1 / temp2;
/* keeps track of seconds */
int j = 1;
/* creates semaphores */
sem_init(&shared.full, 0, 0);
sem_init(&shared.empty, 0, BUFF_SIZE);
sem_init(&shared.mutex, 0, 1);
/* creates producer thread */
for (index = 1; index < NP; index++)
{
/* Create 1 producer */
pthread_create(&idP, NULL, Producer, (void*)index);
}
/* creates 4 consumer threads */
for (index = 1; index < NC; index++)
{
pthread_create(&idC, NULL, Consumer, (void*)index);
}
while(1)
{
sleep(1);
sem_wait(&shared.mutex);
temp1 = (consumed * 3600) / j;
temp2 = (produced * 3600) / j;
printf("\n\nStatistics after %d seconds: \n\n", j);
sem_post(&shared.mutex);
printf("So many consumed per hour: %d\n", temp1);
printf("So many produced per hour: %d\n", temp2);
printf("Ratio of consumed/produced per hour: %d\n", ratio);
j++;
}
sem_destroy(&shared.mutex); // destroy semaphore
pthread_exit(NULL);
}
void *Producer(void *arg)
{
int data, index;
index = (int)arg;
printf("Thread %d in line to produce\n\n", index);
for (produced=0; produced < NITERS; produced++) {
/* Produce item */
data = produced;
printf("[P%d] Producing %d ...\n\n", index, data); fflush(stdout);
// data=produce_item(shared.buf);
/* If there are no empty slots, wait */
sem_wait(&shared.empty);
/* If another thread uses the buffer, wait */
sem_wait(&shared.mutex);
/* put new item in buffer */
shared.buf[shared.in] = data;
shared.in = (shared.in+1)%BUFF_SIZE;
/* leave the critical region */
sem_post(&shared.mutex);
/* Increment the number of full slots */
sem_post(&shared.full);
/* Interleave producer and consumer execution */
if (produced % 2 == 1) sleep(1);
}
return NULL;
}
void *Consumer(void *arg)
{
int data, index;
index = (int)arg;
printf("[C%d] Consuming %d ...\n", index, data); fflush(stdout);
for (consumed=0; consumed < NITERS; consumed++) {
data = consumed;
/* If there are no full slots, wait */
sem_wait(&shared.full);
/* If another thread uses the buffer, wait */
sem_wait(&shared.mutex);
shared.buf[shared.out] = data;
shared.out = (shared.out+1)%BUFF_SIZE;
/* Release the buffer */
sem_post(&shared.mutex);
/* Increment the number of empty slots */
sem_post(&shared.empty);
/* Interleave producer and consumer execution */
if (consumed % 2 == 1) sleep(1);
}
return NULL;
}
אתר שלם
** Semaphores **
Simple locks let us build a number of concurrent programs correctly and
efficiently. Unfortunately, there are some operations that are pretty common
in multithreaded programs that locks alone cannot support (as we will describe
below).
One person who realized this years ago was Edsger Dijkstra, known among other
things for his famous "shortest paths" algorithm in graph theory [1], an early
polemic on structured programming entitled "Goto Statements Considered
Harmful" [2] (what a great title!), and, in the case we will study here, the
introduction of a powerful and flexible synchronization primitive known as the
*semaphore* [3].
In this note, we will first describe the semaphore, and then show how it can
be used to solve a number of important synchronization problems.
[SEMAPHORE: DEFINITION]
A semaphore is as an object with an integer value that we can manipulate with
two routines (which we will call sem_wait() and sem_post() to follow the POSIX
standard). Because the initial value of the semaphore determines its behavior,
before calling any other routine to interact with the semaphore, we must first
initialize it to some value, as this code below does: