We have to write a program, which has 2 threads. One of them reads the content token by token and stores them into a array. The other reads the tokens from the array and writes it into a file.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define MAX 10
int buffer[MAX];
int buf_pos; // the actual position of the buffer
void copy();
int flag; // if flag is 0, the whole content of the file was read
FILE *source;
FILE *dest;
// read the content of a file token by token and stores it into a buffer
void *read_from_file();
// write the content of a buffer token by token into a file
void *write_to_file();
pthread_cond_t condition = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex;
int main( int argc, char *argv[] )
{
flag = 1;
pthread_t writer;
pthread_t reader;
pthread_mutex_init( &mutex, NULL );
if( argc != 3 )
{
printf( "Error\n" );
exit( EXIT_FAILURE );
}
source = fopen( argv[1], "r" );
dest = fopen( argv[2], "w" );
if( source == NULL || dest == NULL )
{
printf( "Error\n" );
exit( EXIT_FAILURE );
}
pthread_create( &reader, NULL, read_from_file, NULL );
pthread_create( &writer, NULL, write_to_file, NULL );
pthread_join( reader, NULL );
pthread_join( writer, NULL );
}
void *read_from_file()
{
int c;
while( ( c = getc( source ) ) != EOF )
{
if( buf_pos < MAX - 1 ) // the buffer is not full
{
pthread_mutex_lock( &mutex );
buffer[buf_pos++] = c;
pthread_mutex_unlock( &mutex );
pthread_cond_signal( &condition );
}
else
{
buffer[buf_pos++] = c; // store the last token
pthread_mutex_lock( &mutex );
pthread_cond_wait( &condition, &mutex ); // wait until the other thread sends a signal
pthread_mutex_unlock( &mutex );
}
}
flag = 0; // EOF
return NULL;
}
void *write_to_file()
{
int c;
while( flag || buf_pos > 0 )
{
if( buf_pos > 0 ) // The buffer is not empty
{
fputc( buffer[0], dest ); // write the first token into file
pthread_mutex_lock( &mutex );
copy();
--buf_pos;
pthread_mutex_unlock( &mutex );
pthread_cond_signal( &condition );
}
else
{
pthread_mutex_lock( &mutex );
pthread_cond_wait( &condition, &mutex );
pthread_mutex_unlock( &mutex );
}
}
return NULL;
}
void copy()
{
int i = 0;
for( ; i < buf_pos - 1; ++i )
buffer[i] = buffer[i + 1];
}
If I want to run the program, it sometimes blocks, but i do not know why. But if the program terminates, the outputfile is the same as the inputfile.
Can somebody explain me, why this could happen?
There are a number of problems with the code, but the reason for your lockups is most probably that you send out signals without the mutex locked, and without checking your condition with the mutex locked. Both are necessary to make sure that you don't end up with lost signals.
As noted by Useless, make sure that you know what your shared variables are, and that they are mutex-protected where necessary. For instance, your buf_pos is modified without protection in your reader thread, and used as a condition for waiting without mutex-protection in both threads.
Also, when doing pthread_cond_wait, you typically want a guard-expression to make sure you don't react to socalled spurios wakeups (have a look at the "Condition Wait Semantics" section at http://linux.die.net/man/3/pthread_cond_wait), and to make sure that the condition you're waiting for hasn't actually happened between testing for it, and starting the wait.
For instance, in your writer thread you could do:
pthread_mutex_lock(&mutex);
while(buf_pos == 0) pthread_cond_wait(&condition, &mutex);
pthread_mutex_unlock(&mutex);
But still, have a thorough look at your program, identify your shared variables, and make sure that they are mutex-protected where necessary. Also, it's far from correct that you only need to mutex-protect shared data for write access. In some cases you can get away with removing the mutex-protection when reading shared variables, but you'll have to analyze your code to make sure that that's actually the case.
Your problem with the deadlock is that you have both threads do this:
pthread_mutex_lock( &mutex );
pthread_cond_wait( &condition, &mutex );
pthread_mutex_unlock( &mutex );
on the same mutex, and the same condition variable. Suppose your reading thread executes those three lines immediately before your writing thread does. They're both going to be waiting on the same condition variable forever. Remember, signaling a condition variable does nothing if there are no threads actually waiting on it at the time. Right now you only avoid deadlock when one of your threads waits on that variable if, by chance, it happens to signal it before waiting for it itself.
Sonicwave's answer does a good job of identifying the other problems in your code, but in general you're not being careful enough about protecting your shared data, and you're not using condition variables properly so your threads are not properly synchronizing with each other. Among other things, if one of your threads is waiting on a condition variable, you need to make sure that there are no circumstances in which the other thread can wait on the same or different one before the other one receives a signal and wakes up.
Related
I'm stuck on this assignment and I just can't get my head around it.
Let's say there's a queue of visitors waiting to get into one of the cars which are also queued. Only one car at a time is supposed to drive up to the platform to pick up 2 waiting people. As soon as 2 visitors enter the car it has to leave the platform.
I need to change the following methods "carArrives()" and "visitorArrives()" from Busy - Waiting to using either only Mutex or Semaphores.
Sorry for any mistakes.
int availableCars = 0;
int availableSeats = 0;
void carArrives(){
while(availableCars > 0){noop;} //exchange this with Mutex/Semaphore
availableCars = 1;
driveToPlatform();
openDoors();
availableSeats = 2;
while(availableSeats > 0){noop;} //exchange this with Mutex/Semaphore
closeDoors();
leavePlatform();
availableCars = 0;
}
void visitorArrives(){
while(availableSeats < 1){noop;} //exchange this with Mutex/Semaphore
enterCar();
availableSeats = availableSeats - 1;
}
if you generate a mutex:
pthread_mutex MyMutex = PTHREAD_MUTEX_INIT;
Then to stop any other part of the program from modifying some resource while the current thread is modifying/accessing the resource:
pthread_mutex_lock( &MyMutex );
// modify or access resource here
pthread_mutex_unlock( &MyMutex );
Note: to be effective, all places in the code that access that resource must use the same 'MyMutex'
regarding:
availableSeats = 2;
while(availableSeats > 0){noop;}
Suggest between locking a mutex for that same resource, to pause a bit, while not locked, to allow some other thread some time to modify the 'availableSeats' value. For instance:
pthread_mutex SeatsFilled = PTHREAD_MUTEX_INIT;
...
pthread_mutex_lock( &SeatsFilled );
availableSeats = 2;
pthread_mutex_unlock( &SeatsFilled );
...
do
{
int numSeats;
pthread_mutex_lock( &SeatsFilled );
numSeats = availableSeats;
pthread_mutex_unlock( &SeatsFilled );
if( !numSeats )
{
nanosleep( 1000 );
}
} while( numSeats );
...
I pass a struct in pthread_create which contains a char* and I lock the main and the thread with mutexes so I can protect this string because when the second thread will be created the string will change and the first thread will use the second string and not the first. Here is the code:
main.c
while( th_num < th_size )
{
pthread_mutex_lock(&lock);
received = 0;
/* Read the desired readable size */
if( read(newsock, &size, sizeof(size)) < 0 )
{ perror("Read"); exit(1); }
/* Read all data */
while( received < size )
{
if( (nread = read(newsock, buffer + received, size - received)) < 0 )
{ perror("Read"); exit(1); }
received += nread;
}
printf("Received string: %s\n",buffer);
Q->receiver = (char*) malloc(sizeof(char)*strlen(buffer)+1);
strncpy(Q->receiver, buffer, strlen(buffer)+1);
if( (err = pthread_create(&thread_server[th_num], NULL, thread_start, (void*) Q)) == true )
{ show_error("pthread_create", err); }
/* -------------------------------------------------- */
th_num++;
pthread_mutex_unlock(&lock);
usleep(500);
}
pthread_server.c
pthread_mutex_lock(&lock);
/*
do some stuff here
*/
pthread_mutex_unlock(&lock);
The program works fine but the problem is that it only works if I put usleep(500). My guess is that the thread cant lock the mutex in time so it needs sleep to do this right. Is there a way to do it without usleep()?
Assuming I don't understand why you need to call pthread_create(); in a mutual exclusion portion of code, your problems is:
you use threads but the flow of your program is approaching to be sequential because of the large mutual exclusion portion of code.
Let X a generic thread in your program.
Without the usleep(500); when the X thread finish it releases the mutex with pthread_mutex_unlock(&lock); but afterwards the thread X reacquires the lock so no one else can access in the mutual exclusion portion of code.
Now I don't know what your shared data is, so I can only suggest you:
1) Reduce the mutual exclusion portion of code, only use it when you access to a shared data;
2) Rethink about your program structure.
How to correctly destroy pthread mutex or rwlock in signal handler? For example - in the code below i has main thread and 3 another threads. All threads do some tasks in infinity loop on some array, using mutexes and locks. Because main thread is also doing some task, the only way to exit from program - using signal handler. But in this way i can't destroy my mutex/rwlock object, because there's no guarantee that object is unlocked. And if I'll try to unlock it, of course one of thread will lock it again. And when i'm trying to launch my program again, that print corrupted result. So how can i solve this problem? There is example of my code with rwlocks:
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include "thread_data.h"
#include "exchange_types.h"
pthread_rwlock_t rwlock;
unsigned int main_time = 500000;
unsigned int shift_time = 1000000;
unsigned int mirror_time = 2000000;
unsigned int count_time = 4000000;
void signal_handler(int signo) {
// Destroying locked lock or mutex is UB
pthread_rwlock_destroy(&rwlock);
exit(1);
}
void* shift_letter_case_async( void* array ) {
while(1) {
if( pthread_rwlock_rdlock(&rwlock) < 0 )
handle_error("rdlock[shift]");
carray_t* arr = (carray_t*) array;
shift_letter_case( arr->array, arr->size );
if( pthread_rwlock_unlock(&rwlock) < 0 )
handle_error("unlock[shift]");
usleep(shift_time);
}
return NULL;
}
void* mirror_array_async( void* array ) {
while(1) {
if( pthread_rwlock_rdlock(&rwlock) < 0 )
handle_error("rdlock[mirror]");
carray_t* arr = (carray_t*) array;
mirror_array( arr->array, arr->size );
if( pthread_rwlock_unlock(&rwlock) < 0 )
handle_error("unlock[mirror]");
usleep(mirror_time);
}
return NULL;
}
void* count_async( void* array ) {
while(1) {
if( pthread_rwlock_wrlock(&rwlock) < 0 )
handle_error("wrlock[count]");
carray_t* arr = (carray_t*) array;
count_upper_letters( arr->array, arr->size );
if( pthread_rwlock_unlock(&rwlock) < 0 )
handle_error("unlock[count]");
usleep(count_time);
}
return NULL;
}
int main( int argc, char** argv ) {
/* Common data */
char letters[ 'z' - 'a' + 1 ];
size_t letter_len;
carray_t transferer;
/* pthread data */
pthread_t threads[3];
/* Initializing array */
letter_len = sizeof(letters);
for( int i = 0; i < letter_len; i++ )
letters[i] = 'a' + i;
transferer.array = letters;
transferer.size = letter_len;
/* Initializing signal handlers */
if ( signal(SIGINT, signal_handler) == SIG_ERR )
handle_error("signal[SIGINT]");
if ( signal(SIGTERM, signal_handler) == SIG_ERR )
handle_error("signal[SIGTERM]");
/* Initializing locks */
if( pthread_rwlock_init(&rwlock, NULL) < 0 )
handle_error("pthread_rwlock_init");
/* Initializing threads */
if( pthread_create( &threads[0], NULL, shift_letter_case_async, &transferer ) != 0 )
handle_error("phtread_create[shift_letter_case]");
if( pthread_create( &threads[1], NULL, mirror_array_async, &transferer ) != 0 )
handle_error("phtread_create[mirror_array]");
if( pthread_create( &threads[2], NULL, count_async, &transferer ) != 0 )
handle_error("phtread_create[count]");
while(1) {
if( pthread_rwlock_wrlock(&rwlock) < 0 )
handle_error("wrlock[main]");
print_array(letters, letter_len);
if( pthread_rwlock_unlock(&rwlock) < 0 )
handle_error("unlock[main]");
usleep(main_time);
}
return 0;
}
Instead of the very risky-sounding approach you propose, consider shutting down by arranging to signal every thread, to which each one responds by performing an orderly shutdown. Have the main thread join the others in that case so that it knows when they have finished; then it can cleanly tear down any persistent synchronization structures, temporary files, etc..
Alternatively, signal the main thread only, and have it -- in a properly synchronized way -- raise a flag that each other thread will recognize as an instruction to shut down, then proceed as above (join the worker threads, then tear down).
I think my first naive attempt at this would be to change the while(1) of the threads and main to while(running) with "running" defined by:
volatile int running = 1;
Change the signal_handler to:
void signal_handler(int signo) {
running = 0;
}
You can join the threads as normal before the return in main. I didn't run this so I may be completely wrong. Also, you may wish to have "if (running)" predicates for the usleep functions.
I have a program that is trying to use create and cancel through an implemented pool.
The creation is as follows:
while (created<threadsNum){
pthread_t newThread;
pthread_struct *st; //Open the thread that handle the deleting of the sessions timeout.
st = (pthread_struct*)malloc(sizeof(pthread_struct));
st->id = created;
st->t = &newThread;
pthread_mutex_lock( &mutex_threadsPool );
readingThreadsPool[created] = st;
pthread_mutex_unlock( &mutex_threadsPool );
if((threadRes1 = pthread_create( &newThread, NULL, pcapReadingThread, (void*)created)))
{
syslog(LOG_CRIT, "Creating Pcap-Reading Thread %d failed.",created);
printf( "Creating Pcap-Reading Thread %d failed.\n",created);
exit(1);
}
syslog(LOG_INFO, "Created Pcap-Reading Thread %d Successfully.",created);
created++;
}
Later I try to cancel them and restart them :
pthread_t* t;
pthread_struct* tstr;
int i;
pthread_mutex_unlock( &mutex_threadsPool );
//first go on array and kill all threads
for(i = 0; i<threadsNum ; i++ ){
tstr = readingThreadsPool[i];
if (tstr!=NULL){
t = tstr->t;
//Reaches here :-)
if (pthread_cancel(*t)!=0){
perror("ERROR : Could not kill thread");
}
else{
printf("Killed Thread %d \n",i);
}
//doesnt reach here
}
}
I checked the addresses in the memory of the created thread in part one and the address of the about to be cancelled thread in the second part..they match..
I read about the thread manager that can't work if one calls killall().
But I don't..
Anyone have any idea?
Thanks
while (created<threadsNum){
pthread_t newThread;
pthread_struct *st;
/* ... */
st->t = &newThread;
/* ... */
}
You've got st->t pointing to a local variable newThread. newThread is only in scope during the current loop iteration. After this iteration st->t will contain an invalid address.
newThread is on the stack, so after it goes out of scope that stack space will be used for other variables. That could be different pthread_ts on successive iterations, or once the loop is over then that stack space will be used for completely different types of values.
To fix this I'd probably change pthread_struct.t to be a pthread_t instead of a pthread_t *, and then change the pthread_create call to:
pthread_create(&st->t, /*...*/)
Also, you should be careful about adding st to the thread pool before you've called pthread_create. It should probably be added after. As it stands, there's a small window where st->t is on the thread pool but has not been initialized.
I want to monitor threads. I used condition variables for send & receive HeartBeat & Acknowlagement signals for that.
scnMonitor_t is a monitor structure. As new threads are added it register with monitor & added to scnThreadlist_t.
monitorHeartbeatCheck is the thread that starts with program,
monitorHeartbeatProcess is API which are added to all thread functions.
Actually my problem is that the index of process is not properly followed
It ends with a wait HB condition for 3rd Thread & dead-lock is created.
what should be the problem?
thanks in advance.
typedef struct scnThreadList_{
osiThread_t thread;
struct scnThreadList_ *next;
} scnThreadList_t;
typedef struct scnMonitor_{
bool started;
osiThread_t heartbeatThread;
osiMutex_t heartbeatMutex;
osiMutex_t ackMutex;
osiCond_t heartbeatCond;
scnThreadList_t *threads;
} scnMonitor_t;
static scnMonitor_t *s_monitor = NULL;
// Main heartbeat check thread
void* monitorHeartbeatCheck( void *handle )
{
scnThreadList_t *pObj = NULL;
static int idx = 0;
static bool waitAck = false;
while ( 1 ) {
pObj = s_monitor->threads;
while ( pObj && ( pObj != s_monitor->heartbeatThread ) ) { //skip it-self from monitoring.
++idx;
printf("\"HB Check No.%d\"\n",idx);
// send heartbeat
usleep( 250 * 1000 );
pthread_mutex_lock( s_monitor->heartbeatMutex, 1 );
pthread_cond_signal( s_monitor->heartbeatCond );
printf("-->C %d HB sent\n",idx);
pthread_mutex_unlock( s_monitor->heartbeatMutex );
// wait for ACK
while( !waitAck ){
pthread_mutex_lock( s_monitor->ackMutex, 1 );
printf("|| C %d wait Ack\n",idx);
waitAck = true;
pthread_cond_wait( s_monitor->heartbeatCond, s_monitor->ackMutex );
waitAck = false;
printf("<--C %d received Ack\n",idx);
pthread_mutex_unlock( s_monitor->ackMutex );
LOG_INFO( SCN_MONITOR, "ACK from thread %p \n", pObj->thread );
}
pObj = pObj->next;
}
} // while, infinite
return NULL;
}
// Waits for hearbeat and acknowledges
// Call this API from every thread function that are registered
int monitorHeartbeatProcess( void )
{
static int id = 0;
static bool waitHb = false;
++ id;
printf("\"HB Process No.%d\"\n",id);
// wait for HB
while(!waitHb){
pthread_mutex_lock( s_monitor->heartbeatMutex, 1 );
printf("|| P %d wait for HB\n",id);
waitHb = true;
pthread_cond_wait( s_monitor->heartbeatCond, s_monitor->heartbeatMutex );
waitHb = false;
printf("<--P %d HB received \n",id);
pthread_mutex_unlock( s_monitor->heartbeatMutex );
}
// send ACK
uleep( 250 * 1000 );
pthread_mutex_lock( s_monitor->ackMutex, 1 );
pthread_cond_signal( s_monitor->heartbeatCond );
printf("-->P %d ACK sent\n",id);
pthread_mutex_unlock( s_monitor->ackMutex );
return 1;
}
You should always associate only one mutex with a condition at a time. Using two different mutexes with the same condition at the same time could lead to unpredictable serialization issues in your application.
http://publib.boulder.ibm.com/infocenter/iseries/v5r4/index.jsp?topic=%2Fapis%2Fusers_78.htm
You have 2 different mutexes with your condition heartbeatCond.
I think you are experiencing a deadlock here. The thread calling monitorHeartbeatProcess() takes mutex on heartbeatMutex and waits for signal on the condition variable, heartbeatCond. While thread calling monitorHeartbeatCheck() takes mutex on ackMutex and waits for sognal on condition variable, heartbeatCond. Thus both threads waits on the condition variable heartbeatCond causing deadlock. If you are so particular in using two mutexes, why not two condition variables?