Im trying to complete what I thought would be simple task but after several days have reached a breaking point.
I am trying to simulate a database using multiple readers and a single writer. When I run my program it deadlocks.
I was trying to base it on this algorithm:
1 semaphore accessMutex; // Initialized to 1
2 semaphore readersMutex; // Initialized to 1
3 semaphore orderMutex; // Initialized to 1
4
5 unsigned int readers = 0; // Number of readers accessing the resource
6
7 void reader()
8 {
9 P(orderMutex); // Remember our order of arrival
10
11 P(readersMutex); // We will manipulate the readers counter
12 if (readers == 0) // If there are currently no readers (we came first)...
13 P(accessMutex); // ...requests exclusive access to the resource for readers
14 readers++; // Note that there is now one more reader
15 V(orderMutex); // Release order of arrival semaphore (we have been served)
16 V(readersMutex); // We are done accessing the number of readers for now
17
18 ReadResource(); // Here the reader can read the resource at will
19
20 P(readersMutex); // We will manipulate the readers counter
21 readers--; // We are leaving, there is one less reader
22 if (readers == 0) // If there are no more readers currently reading...
23 V(accessMutex); // ...release exclusive access to the resource
24 V(readersMutex); // We are done accessing the number of readers for now
25 }
26
27 void writer()
28 {
29 P(orderMutex); // Remember our order of arrival
30 P(accessMutex); // Request exclusive access to the resource
31 V(orderMutex); // Release order of arrival semaphore (we have been served)
32
33 WriteResource(); // Here the writer can modify the resource at will
34
35 V(accessMutex); // Release exclusive access to the resource
36 }
However I am trying to implement it using only pthreads rather than semaphores. As you can expect here is what the mess turned out to be:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define MAX 5 //size of buffer
pthread_mutex_t mutex; //pthread_mutex type
pthread_cond_t condw, condr; //reader/writer cond var
int buffer = 0, rc = 0;
pthread_mutex_t db; //pthread_mutex type
//reader-writer header:
void* writer(void* ptr);
void* reader(void* ptr);
void use_data();
void write_database();
void readdb();
int main(int argc, char** argv)
{
pthread_t read,write;
//allow signal back and forth
pthread_mutex_init(&mutex,0); //init mutex
pthread_cond_init(&condw, 0); //init writer
pthread_cond_init(&condr,0); //init reader
pthread_mutex_init(&db,0); //init db
//this calls the void* reader function
pthread_create(&write,0,writer,0); //create thread
pthread_create(&read,0,reader,0); //create thread
//let them join
pthread_join(read,0);
pthread_join(write,0);
//destroy them
pthread_cond_destroy(&condw);
pthread_cond_destroy(&condr);
pthread_mutex_destroy(&db);
pthread_mutex_destroy(&mutex);
return 0;
}//end main
void* reader(void* arg)
{
while(1) //if there is a reader lock the db
{
pthread_mutex_lock(&mutex);
rc++;
if(rc==1)
{
pthread_mutex_lock(& db);
}
pthread_mutex_unlock(&mutex);
readdb();
pthread_mutex_lock(&mutex);
rc--;
if(rc==0)
{
pthread_mutex_unlock(&db);
}
pthread_mutex_unlock(&mutex);
use_data();
}
}
void* writer(void* arg)
{
while(1) //unlock the db
{
pthread_mutex_lock(&db);
write_database();
pthread_mutex_unlock(&db);
}
}
void use_data(){}
void write_database(){}
void readdb(){}
Any help with a working solution and explanation where we went wrong is appreciated as it would help me and my colleagues out. Regards.
The problem is that your source algorithm relies on the fact that one thread locks the
accessMutexlock, and another thread then may unlock it. This is allowable with semaphore-based mutexes, but it is not allowed for pthreads mutexes.There are semaphores in pthreads, provided by the
sem_init(),sem_post()andsem_wait()functions. You could use these to write a direct implementation of the source algorithm, and it should work correctly.Alternately, pthreads also provides a native read-writer lock type – see the functions
pthread_rwlock_init(),pthread_rwlock_rdlock(),pthread_rwlock_wrlock()andpthread_rwlock_unlock(). You could use this for a very simple implementation, but obviously this is missing the point if it’s supposed to be a learning exercise.