I was trying to implement a checkpointing scheme based on multithreaded fork using fork combined with setjmp/longjmp. I was hoping my solution would work but as expected it didn't. The code is shown below with an example usage for checkpoint/rollback.
The main idea is to allocate stacks for the threads myself, as done by using the function pthread_create_with_stack and then just use a fork from the main thread. The forked process (checkpoint) is suspended at the beginning and when awoken (rollbacking), the main thread of the forked process recreates the threads by calling pthread_create and use the same stacks as threads in original process. Also longjmp is done in the thread routine at the beginning, so as to jump to the same point in the code when process was forked as a checkpoint. Note that all setjmp calls are done inside function my_pthread_barrier_wait so that no thread has acquired a lock.
I think the problem here is setjmp/lonjmp. Will getcontext/savecontext/makecontext help here, or anything else? Can even setjmp/longjmp be used in such a way here that it works? Any solution will be greatly appreciated.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/types.h>
#include <setjmp.h>
#define PERFORM_JMP
#define NUM_THREADS 4
void *stackAddr[NUM_THREADS];
pthread_t thread[NUM_THREADS];
jmp_buf buf[NUM_THREADS];
pthread_attr_t attr[NUM_THREADS];
pthread_barrier_t bar;
sem_t sem;
pid_t cp_pid;
int rollbacked;
int iter;
long thread_id[NUM_THREADS];
void *BusyWork(void *t);
void sig_handler(int signum)
{
printf( "signal_handler posting sem!\n" );
sem_post( &sem );
}
int pthread_create_with_stack( void *(*start_routine) (void *), int tid )
{
const size_t STACKSIZE = 0xC00000; //12582912
size_t i;
pid_t pid;
int rc;
printf( "tid = %d\n", tid );
pthread_attr_init( &attr[tid] );
stackAddr[tid] = malloc(STACKSIZE);
pthread_attr_setstack( &attr[tid], stackAddr[tid], STACKSIZE );
thread_id[tid] = tid;
rc = pthread_create( &thread[tid], &attr[tid], start_routine, (void*)&thread_id[tid] );
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
return rc;
}
pid_t checkpoint()
{
pid_t pid;
int t, rc;
switch (pid=fork())
{
case -1:
perror("fork");
break;
case 0: // child process starts
sem_wait( &sem );
rollbacked = 1;
printf( "case 0: rollbacked = 1, my pid is %d\n", getpid() );
for( t = 1; t < NUM_THREADS; t++ )
{
printf( "checkpoint: creating thread %d again\n", t );
rc = pthread_create( &thread[t], &attr[t], BusyWork, (void*)&thread_id[t] );
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
return 1; // child process ends
default: // parent process starts
return pid;
}
}
void restart_from_checkpoint( pid_t pid )
{
printf( "Restart_from_checkpoint, sending signal to %d!\n", pid );
kill( pid, SIGUSR1 );
exit( 0 );
}
void take_checkpoint_or_rollback( int sig_diff )
{
if ( cp_pid )
{
if ( sig_diff )
{
printf( "rollbacking\n" );
if ( !rollbacked )
restart_from_checkpoint( cp_pid );
}
else
{
kill( cp_pid, SIGKILL );
cp_pid = checkpoint();
printf( "%d: cp_pid = %d!\n", getpid(), cp_pid );
}
}
else
cp_pid = checkpoint();
}
void my_pthread_barrier_wait( int tid, pthread_barrier_t *pbar )
{
pthread_barrier_wait( pbar );
#ifdef PERFORM_JMP
if ( tid == 0 )
{
if ( !rollbacked )
{
take_checkpoint_or_rollback( ++iter == 4 );
}
}
if ( setjmp( buf[tid] ) != 0 ) {}
else {}
printf( "%d: %d is waiting at the second barrier!\n", getpid(), tid );
#endif
pthread_barrier_wait( pbar );
}
void *BusyWork(void *t)
{
volatile int i;
volatile long tid = *((long*)t);
volatile double result = 0.0;
printf( "thread %ld in BusyWork!\n", tid );
#ifdef PERFORM_JMP
if ( rollbacked )
{
printf( "hmm, thread %ld is now doing a longjmp, goodluck!\n", tid );
longjmp( buf[tid], 1 );
}
#endif
printf("Thread %ld starting...\n",tid);
for ( i = 0; i < 10; i++)
{
result += (tid+1) * i;
printf( "%d: tid %ld: result = %g\n", getpid(), tid, result );
my_pthread_barrier_wait(tid, &bar);
}
printf("Thread %ld done. Result = %g\n", tid, result);
//pthread_exit((void*) t);
}
int main (int argc, char *argv[])
{
int rc;
long t;
void *status;
/* Initialize and set thread detached attribute */
pthread_barrier_init(&bar, NULL, NUM_THREADS);
#ifdef PERFORM_JMP
signal(SIGUSR1, sig_handler);
sem_init( &sem, 0, 0 );
#endif
for( t = 1; t < NUM_THREADS; t++ )
{
printf( "Main: creating thread %ld\n", t );
rc = pthread_create_with_stack( BusyWork, t ); // This is the line 52
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
thread_id[0] = 0;
BusyWork( &thread_id[0] );
/* Free attribute and wait for the other threads */
for(t=1; t<NUM_THREADS; t++)
{
rc = pthread_join(thread[t], &status);
if (rc)
{
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
printf("Main: completed join with thread %ld having a status"
"of %ld\n",t,(long)status);
}
printf("Main: program completed. Exiting.\n");
pthread_exit(NULL);
}
What you're trying to do is simply impossible. fork is fundamentally incompatible with synchronization. Even if you could recreate threads reliably in the child process, they would have new thread ids, and thus they would not be the owners of the locks they're supposed to own.
The only way to do checkpointing is with advanced operating system support for it. This would have to include separate pid namespaces, so that the checkpointed copy of the program would have the same pid, and all its threads would have the same thread ids. Even then, if it's performing communication with other processes or the outside world, it won't work. I believe there are some tools for doing this on Linux, but I'm not familiar with them, and at this point you're getting to level of hacks where it's appropriate to ask if there's a better way to achieve what you're trying to do.
Related
I'm trying to write a program which will spawn an arbitrary number of threads, similar to the code I have in Convert a process based program into a thread based version?, which uses processes to do what I'm trying to accomplish, so far I have the following code, I'm getting a lot of warnings currently, but I'm really wondering if I'm approaching what I'm trying to do somewhat correctly.
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
void *runner(void *param); //the thread
int main(int argc, char *argv[]) {
pthread_t tid = gettid();
pthread_attr_t attr;
if (argc != 2){
fprintf(stderr, "Usage: a.out <integer value>\n");
return -1;
}
if (atoi(argv[1]) < 0) {
fprintf(stderr, "Argument %d must be non negative\n", atoi(argv[1]));
return -1;
}
printf("My thread identifier is: %d\n", tid);
// default attributes
pthread_attr_init(&attr);
// create the thread
pthread_create(&tid, &attr, runner, argv[1]);
// wait for the thread to exit
pthread_join(tid, NULL);
}
void *runner(void *param){
//int i, upper = atoi(param);
int i;
srand48(gettid());
int max = nrand()%100;
if (max > 0){
for (i=1; i<=max; i++){
printf("Child %d executes iteration\n", param, i);
}
}
pthread_exit(0);
}
Appreciate any guidance I can get with this!
If I understand your objective, you want to create the number of threads as the command line parameter indicates.
(remembering that any specific OS can only support a fixed number of threads, which varies depending on the OS, so I will not validate the magnitude that number here.)
the following proposed code:
cleanly compiles
performs the desired functionality
documents why each header file is included
checks for error indications returned from C library functions, like pthread_create()
and now the proposed code:
#include <stdio.h> // printf(), perror(), NULL
#include <pthread.h> // pthread_create(), pthread_join(), pthread_t
#include <stdlib.h> // exit(), EXIT_FAILURE, atof()
void *runner(void *param); //the thread
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s <integer value>\n", argv[0]);
exit( EXIT_FAILURE );
}
// might want to use: `strtol()` rather than `atoi()`
// so can check for errors
size_t maxThreads = (size_t)atoi(argv[1]);
pthread_t tid[ maxThreads ];
for( size_t i=0; i<maxThreads; i++ )
{
tid[i] = 0;
}
// create the threads
for( size_t i=0; i<maxThreads; i++ )
{
if( pthread_create( &tid[i], NULL, runner, (void *)i ) )
{
perror( "pthread_create failed" );
}
}
// wait for each thread to exit
for( size_t i = 0; i<maxThreads; i++ )
{
// if thread was created, then wait for it to exit
if( tid[i] != 0 )
{
pthread_join( tid[i], NULL );
}
}
}
void *runner(void *arg)
{
size_t threadNum = (size_t)arg;
printf( "in thread: %zu\n", threadNum );
pthread_exit( NULL );
}
a run with no command line parameter results in: (where the executable is named: untitled
Usage: ./untitled <integer value>
a run with a command line parameter of 10 results in:
in thread: 0
in thread: 4
in thread: 2
in thread: 6
in thread: 1
in thread: 5
in thread: 7
in thread: 8
in thread: 9
in thread: 3
which makes it clear that threads are run in no particular order
1: I see no function called gettid()
pthread_t tid = gettid();
srand48(gettid());
2: You cannot print pthread_t as an integer, it's a structure
printf("My thread identifier is: %d\n", tid);
3: it's rand(), I have not seen nrand() before.
int max = nrand()%100;
Fix these and edit the question if required.
I have to send signal p1 -> p2 -> p3 ->p1 ... in order to change the value of shared file. however p3 -> p1 is not working(p1 doesn't catch the signal). I put sleep to make time difference between each transition but idk what's wrong.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
void sig_usr (int signo)
{
printf("%d\n",getpid());
// longjmp(jumpbuffer,1);
}
int main(int argc, char **argv)
{
signal(SIGUSR1, sig_usr);
jmp_buf jumpbuffer;
pid_t next,ppid,granmaduh;
granmaduh = getpid();
if ((next = fork()) <0 )
{
fprintf(stderr, "fork() error");
exit(1);
}
else if (next == 0 )
{
next = fork();
if (next >0)
{
sleep(6);
}
else
{
next = granmaduh;
sleep(10);
}
}
sleep(2);
printf("%d\n",next);
//setjmp(jumpbuffer);
kill(next, SIGUSR1);
exit(1);
}
#include <signal.h>
#include <stdio.h>
#include <sys/wait.h>
#include <errno.h>
static void signal_handler(int);
int i, pid1, pid2,pid3, status;
int main( int argc, char *argv[], char *env[] )
{
int exit_status;
if( signal( SIGUSR1, signal_handler) == SIG_ERR )
{
printf("Pærent: Unable to create handler for SIGUSR1\n");
}
// if( signal( SIGUSR2, signal_handler) == SIG_ERR )
// {
// printf("Pærent: Unable to create handler for SIGUSR2\n");
// }
printf( "Parent pid = %d\n", pid1=getpid() );
if( (pid2 = fork()) == 0 )
{
printf( "Child pid = %d\n", getpid() );
//printf( "Child: %d sending parent SIGUSR1\n", getpid() ); //kill( pid1, SIGUSR1 );
if( (pid3 = fork()) == 0 )
{
printf( "GranChild pid = %d\n", getpid() );
printf( "Child: %d sending parent SIGUSR1\n", getpid() ); kill( pid2, SIGUSR1 );
}
for( ;; ); /* loop forever */
}
else
{
/*
* This waits for ANY child to die. It doesn't matter if the child
* dies normally or from a signal. The satus information is then
* stored in the status integer.
*
* If you want to wait on a particular process use waitpid():
* waitpid( childPID, &status, 0 );
* is the common usage.
*
* Solaris acts weirdly when a signal is given to the parent process.
* Therefore we place the wait() inside a while loop so that wait()
* will not return before the child has died.
*/
/* while( (wait( &status ) == -1) && (errno == EINTR) ) {} */
wait(&status);
/*
* The information in status is *NOT* the return code!! To make use
* of the information we must macros to extract the needed
* information.
*/
/* WIFEXITED() determines if the process exited normally (returned a
* number). This can be done through a return or exit()
*/
if( WIFEXITED( status ) )
{
/*
* Now we know the process exited properly so we can get the
* return value
*
* Note that WEXITSTATUS only retuns the lower 8 bits! That means
* that if we ever expect a negative number then we have to count
* the 8th bit as a sign bit.
*/
exit_status = WEXITSTATUS( status );
/*
* Since we expect negative numbers...
*
* If the exit_status is greater than 2^7 (128), thæn the eigth bit
* is a 1, so we subtract 2^8 (256) from it to make it look like
* a negative number.
*/
if( exit_status > 128 )
{
exit_status -= 256;
}
printf( "Child return - %d\n", WEXITSTATUS( status ) );
}
else
{
/* Well it didn't exit properly. Was it a signal? */
if( WIFSIGNALED( status ) )
{
/*
* Yes. A signal killed the child process. Now we can extract
* the signal information from status
*/
printf( "Child died on signal - %d\n", WTERMSIG( status ));
}
}
/*
* There are two other macros most UNIXes use. They are:
* WIFSTOPPED() and WSTOPSIG(). See the man pages on the dells for
* more information.
*
* To wait on a particular pid - see waitpid()
*/
}
return 0;
}
static void signal_handler(int signo)
{
/* signo contains the signal number that was received */
switch( signo )
{
/* Signal is a SIGUSR1 */
case SIGUSR1:
printf( "Process %d: received SIGUSR1 \n", getpid() );
if(pid1==getpid()) /* it is the parent */
{
printf( "Process %d is passing SIGUSR1 to %d...\n", getpid(),pid2 );
kill( pid2, SIGUSR1 );
}
else if(pid2==getpid()) /* it is the child */
{
printf( "Process %d is passing SIGUSR2 to itself...\n", getpid());
kill(getpid(), SIGUSR2);
}
else
{
printf( "Process %d is passing SIGUSR2 to itself...\n", getpid());
kill(pid3, SIGUSR2);
}
break;
/* It's a SIGUSR2 */
case SIGUSR2:
printf( "Process %d: received SIGUSR2 \n", getpid() );
if(pid1==getpid())
{
printf( "Process %d is passing SIGUSR2 to %d...\n", getpid(),pid2 );
kill( pid2, SIGUSR2 );
}
else if(pid2==getpid())/* it is the child */
{
printf( "Process %d is passing SIGUSR2 to %d...\n", getpid(),pid3 );
kill(pid3, SIGINT);
}
else /* it is the child */
{
printf( "Process %d is passing SIGUSR2 to %d...\n", getpid() );
kill(getpid(), SIGINT);
}
break;
default:
break;
}
return;
}
I am new to multithread programming. I tried to print sequence of numbers using even and odd number printing threads, running in parallel. When executed, the code enters a deadlock. Can anyone help me to solve this.
#include<stdio.h>
#include<pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t even, odd;
void printfun1(void *pnt);
void printfun2(void *pnt);
main()
{
pthread_t pthread1, pthread2;
int ret1, ret2;
char *message = "thread 1";
char *message2 = "thread 2";
ret1 = pthread_create(&pthread1, NULL, printfun1, (void *)message);
if(ret1)
{
printf("thread creation failed");
}
ret2 = pthread_create(&pthread2, NULL, printfun2,(void*) message2);
if(ret2)
{
printf("thread creation failed");
}
pthread_join(pthread1, NULL);
pthread_join(pthread2, NULL);
exit(0);
}
void printfun1(void *ptr)
{
char* message = ptr;
int counter = -1;
while(counter < 50)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&even, &mutex);
counter += 2;
printf("%d \n", counter);
pthread_cond_signal(&odd);
pthread_mutex_unlock(&mutex);
usleep( 1000000);
}
}
void printfun2(void *ptr)
{
char* message = ptr;
int counter2 = 0;
pthread_cond_signal(&even);
while(counter2 < 50)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&odd, &mutex);
counter2 += 2;
printf("%d \n", counter2);
pthread_cond_signal(&even);
pthread_mutex_unlock(&mutex);
usleep( 1000000);
}
}
There are at least a couple things wrong with the program:
You never initialize the condition variables:
pthread_cond_init(&even, NULL);
pthread_cond_init(&odd, NULL);
You can reach a deadlock if you signal a condition when the other thread isn't waiting on that condition. Normally, when you use pthread_cond_wait(), you also are checking some other shared variable in a while loop. I rewrote your program to demonstrate this:
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t even = PTHREAD_COND_INITIALIZER;
pthread_cond_t odd = PTHREAD_COND_INITIALIZER;
void *printfun1(void *pnt);
void *printfun2(void *pnt);
int main(void)
{
pthread_t pthread1, pthread2;
int ret1, ret2;
ret1 = pthread_create(&pthread1, NULL, printfun1, NULL);
if(ret1)
{
printf("thread creation failed");
}
ret2 = pthread_create(&pthread2, NULL, printfun2, NULL);
if(ret2)
{
printf("thread creation failed");
}
pthread_join(pthread1, NULL);
pthread_join(pthread2, NULL);
}
int counter = 0;
void *printfun1(void *ptr)
{
while(counter < 50)
{
pthread_mutex_lock(&mutex);
while ((counter & 1) == 1)
pthread_cond_wait(&even, &mutex);
printf("%d \n", counter);
counter++;
pthread_cond_signal(&odd);
pthread_mutex_unlock(&mutex);
usleep( 1000000);
}
return NULL;
}
void *printfun2(void *ptr)
{
while(counter < 50)
{
pthread_mutex_lock(&mutex);
while ((counter & 1) == 0)
pthread_cond_wait(&odd, &mutex);
printf("%d \n", counter);
counter++;
pthread_cond_signal(&even);
pthread_mutex_unlock(&mutex);
usleep( 1000000);
}
return NULL;
}
Now you can see how deadlock is avoided. A thread only starts waiting on a condition when it knows that it needs to wait on the condition. So even if the second thread signalled the condition when the first thread wasn't waiting on it, it doesn't matter.
I think that to do the job right, you need three mutexes and three condition variables. The odd thread must keep the odd mutex locked for the entire duration of the program. The only time the odd mutex is unlocked is when the odd thread is waiting on its condition. Likewise, the even thread needs to keep the even mutex locked for the duration.
And you need a main mutex and a main condition variable, so that the odd and even threads can signal main after locking their respective mutexes.
After the odd and even threads
- are up and running
- have locked their mutexes
- and are waiting on their condition variables (which unlocks the mutex)
then main can signal the odd thread one time to get things started.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t mainMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t oddMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t evenMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t mainCond = PTHREAD_COND_INITIALIZER;
pthread_cond_t oddCond = PTHREAD_COND_INITIALIZER;
pthread_cond_t evenCond = PTHREAD_COND_INITIALIZER;
void *printOdd( void *arg )
{
pthread_mutex_lock( &oddMutex ); // grab the odd mutex
pthread_mutex_lock( &mainMutex ); // signal main that the odd thread
pthread_cond_signal( &mainCond ); // is locked and ready for action
pthread_mutex_unlock( &mainMutex );
for ( int counter = 1; counter < 50; counter += 2 )
{
pthread_cond_wait( &oddCond, &oddMutex ); // wait for the odd signal
printf( "%d\n", counter );
pthread_mutex_lock( &evenMutex ); // signal the even thread
pthread_cond_signal( &evenCond );
pthread_mutex_unlock( &evenMutex );
usleep( 100000 );
}
pthread_mutex_unlock( &oddMutex );
return NULL;
}
void *printEven( void *arg )
{
pthread_mutex_lock( &evenMutex ); // grab the even mutex
pthread_mutex_lock( &mainMutex ); // signal main that the even thread
pthread_cond_signal( &mainCond ); // is locked and ready for action
pthread_mutex_unlock( &mainMutex );
for ( int counter = 2; counter < 50; counter += 2 )
{
pthread_cond_wait( &evenCond, &evenMutex ); // wait for the even signal
printf( "%d\n", counter );
pthread_mutex_lock( &oddMutex ); // signal the odd thread
pthread_cond_signal( &oddCond );
pthread_mutex_unlock( &oddMutex );
usleep( 100000 );
}
pthread_mutex_unlock( &evenMutex );
return NULL;
}
int main( void )
{
pthread_t id1, id2;
pthread_mutex_lock( &mainMutex ); // grab the main mutex
if ( pthread_create( &id1, NULL, printOdd, NULL ) != 0 ) // create the odd thread
exit( 1 );
pthread_cond_wait( &mainCond, &mainMutex ); // wait for the signal from the odd thread
if ( pthread_create( &id2, NULL, printEven, NULL ) != 0 ) // create the even thread
exit( 1 );
pthread_cond_wait( &mainCond, &mainMutex ); // wait for the signal from the even thread
pthread_mutex_unlock( &mainMutex ); // startup has completed, release the main mutex
pthread_mutex_lock( &oddMutex ); // signal the odd thread to get things rolling
pthread_cond_signal( &oddCond );
pthread_mutex_unlock( &oddMutex );
pthread_join( id1, NULL ); // wait for the threads to finish
pthread_join( id2, NULL );
exit( 0 );
}
First thing is condition variable is not initialized to "PTHREAD_COND_INTIALIAZER". Coming to the program, in the first thread, i think pthread_mutex_unlock should come before pthread_cond_signal
the following code
--removes the unneeded system function calls
--properly handles the mutex creation/locking/unlocking/destruction
--prints even/odd values from 0 through 49
--properly handles logging of errors
--corrects the compiler warning about undefined function exit()
--stops threads getting locked in the inner while loop
--properly defines the top thread functions as 'void*' rather than 'void'
--properly sets parameters to pthread_create()
--properly exits the threads via pthread_exit()
--and several other minor fixes
#include <stdio.h>
#include <stdlib.h> // exit(), EXIT_FAILURE
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *printfun1(void *);
void *printfun2(void *);
main()
{
pthread_t pthread1, pthread2;
int ret1, ret2;
ret1 = pthread_create(&pthread1, NULL, &printfun1, (void *)message);
if(ret1)
{
perror("thread 1 creation failed");
exit( EXIT_FAILURE );
}
ret2 = pthread_create(&pthread2, NULL, &printfun2,(void*) message2);
if(ret2)
{
perror("thread 2 creation failed");
exit( EXIT_FAILURE );
}
pthread_join(pthread1, NULL);
pthread_join(pthread2, NULL);
pthread_mutex_destroy(&mutex);
return 0;
} // end function: main
int counter = 0;
// Note:
// 1) 0 is even so should be printed
// 2) 50 is beyond the range, so should not be printed
// 3) use do{...}while so program will exit when done,
// rather than getting locked in wait loop
void *printfun1(void *ptr)
{
do
{
while( (counter & 1) == 0 )
{
usleep(100);
}
pthread_mutex_lock(&mutex);
printf("%d \n", counter);
counter++;
pthread_mutex_unlock(&mutex);
} while( counter < 50 );
pthread_exit( 0 );
} // end function: printfun1
void *printfun2(void *ptr)
{
do
{
while( (counter & 1) == 1 )
{
usleep(100);
}
pthread_mutex_lock(&mutex);
printf("%d \n", counter);
counter++;
pthread_mutex_unlock(&mutex);
} while( counter < 50 );
pthread_exit( 0 );
} // end function: printfun2
I have this program in C:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define OUTPUTNAME "write.out"
#define OUTPUTNAME1 "fprint.out"
void *syscall_writer_function();
void *stdlibrary_writer_function();
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
int counter = 0;
main()
{
int rc1, rc2;
pthread_t thread1, thread2;
/* Create independent threads each of which will execute functions */
if( (rc1=pthread_create( &thread1, NULL, &stdlibrary_writer_function, NULL)) )
{
printf("Thread creation failed: %d\n", rc1);
}
if( (rc2=pthread_create( &thread2, NULL, &syscall_writer_function, NULL)) )
{
printf("Thread creation failed: %d\n", rc2);
}
pthread_join( thread1, NULL);
pthread_join( thread2, NULL);
exit(EXIT_SUCCESS);
}
void *syscall_writer_function()
{
long i;
int fd;
if ((fd=open(OUTPUTNAME,O_WRONLY|O_CREAT,0644)) < 0){
fprintf(stderr,"Can't open %s. Bye.\n",OUTPUTNAME);
exit(1);
}
for (i=0; i<50000; i++) { /* write 50,000 Ys with write */
if (write(fd,"Y",1) < 1) {
fprintf(stderr,"Can't write. Bye\n");
exit(1);
}
}
pthread_mutex_lock( &mutex1 );
counter++;
printf("Syscall finished\n");
printf("Counter value: %d\n",counter);
close(fd);
exit(0);
pthread_mutex_unlock( &mutex1 );
}
void *stdlibrary_writer_function()
{
long i;
FILE *fp;
if ((fp=fopen(OUTPUTNAME1,"w")) == NULL) {
fprintf(stderr,"Can't open %s. Bye.\n",OUTPUTNAME1);
exit(1);
}
for (i=0; i<400000; i++) { /* write 400,000 Xs with fprintf */
if (fprintf(fp,"X") < 1) {
fprintf(stderr,"Can't write. Bye\n");
exit(1);
}
}
pthread_mutex_lock( &mutex2 );
counter++;
printf("Stdlibrary finished\n");
printf("Counter value: %d\n",counter);
fclose(fp);
exit(0);
pthread_mutex_unlock( &mutex2 );
}
It should give output from both the threads like:
Syscall finished
Counter value: 1
Stdlibrary finished
Counter value: 2
or vice versa with stdlibrary first and syscall second.
But, it only gives output like the following:
Syscall finished
Counter value: 1
Why is this happening? What is wrong?
I am trying to use pthread mutex variables and barrier to synchronize the output of my program, but it is not working the way I want it to. Each thread is seeing its final value every 20 values (coming from the for loop) which is alright but I'm trying to make them all get to the same final value (if using 5 threads, all of them should see 100 as final value, with 4 threads, 80, etc)
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int SharedVariable =0;
void *SimpleThread(void *args)
{
int num,val,rc;
int which =(int)args;
rc = pthread_mutex_lock(&mutex1);
for(num=0; num<20; num++){
#ifdef PTHREAD_SYNC
if(random() > RAND_MAX / 2)
usleep(10);
#endif
//pthread_mutex_lock(&mutex1);
val = SharedVariable;
printf("*** thread %d sees value %d\n", which, val);
//pthread_mutex_lock(&mutex1);
SharedVariable = val+1;
pthread_mutex_unlock(&mutex1);
}
val=SharedVariable;
printf("Thread %d sees final value %d\n", which, val);
//pthread_mutex_destroy(&mutex1);
//pthread_exit((void*) 0);
//pthread_mutex_unlock(&mutex1);
}
int main (int argc, char *argv[])
{
if(atoi(argv[1]) > 0){
int num_threads = atoi(argv[1]);
//pthread_mutex_init(&mutex1, NULL);
pthread_t threads[num_threads];
int rc;
long t;
rc = pthread_mutex_lock(&mutex1);
for(t=0; t< num_threads; t++){
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, SimpleThread, (void* )t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
//pthread_join(thread1);
}
rc= pthread_mutex_unlock(&mutex1);
}
else{
printf("ERROR: The parameter should be a valid positive number.");
exit(-1);
}
pthread_mutex_destroy(&mutex1);
pthread_exit(NULL);
}
Any suggestions or help is greatly appreciated!
Thanks in advanced!
You need to use a barrier (pthread_barrier_wait()) before checking for the final value - this ensures that no thread will proceed until all threads have reached the barrier.
In addition, you should be calling pthread_join() to wait for the threads to finish, and you only need to hold the mutex around the increment:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_barrier_t barrier1;
int SharedVariable = 0;
void *SimpleThread(void *args)
{
int num,val;
int which = (int)args;
for(num = 0; num < 20; num++) {
#ifdef PTHREAD_SYNC
if(random() > RAND_MAX / 2)
usleep(10);
#endif
pthread_mutex_lock(&mutex1);
val = SharedVariable;
printf("*** thread %d sees value %d\n", which, val);
SharedVariable = val + 1;
pthread_mutex_unlock(&mutex1);
}
pthread_barrier_wait(&barrier1);
val = SharedVariable;
printf("Thread %d sees final value %d\n", which, val);
return 0;
}
int main (int argc, char *argv[])
{
int num_threads = argc > 1 ? atoi(argv[1]) : 0;
if (num_threads > 0) {
pthread_t threads[num_threads];
int rc;
long t;
rc = pthread_barrier_init(&barrier1, NULL, num_threads);
if (rc) {
fprintf(stderr, "pthread_barrier_init: %s\n", strerror(rc));
exit(1);
}
for (t = 0; t < num_threads; t++) {
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, SimpleThread, (void* )t);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
for (t = 0; t < num_threads; t++) {
pthread_join(threads[t], NULL);
}
}
else {
printf("ERROR: The parameter should be a valid positive number.\n");
exit(-1);
}
return 0;
}
Try to move the pthread_mutext_unlock(&mutext1) out of the for loop in your SimpleThread. You lock once and unlock mutiple(20) times in your original code.
Alternatively, you could move pthread_mutex_lock(&mutext1) into the for loop, just before you read and modify your SharedVariable. In this case, each thread's add-by-one operation may not consecutive but each thread will get the correct final value.
And before you read the final value of the SharedVariable, use a barrier to wait all the threads finish their job.