I wrote a simple c program using pthreads. On my laptop the multithreaded program runs as expected. When running on desktop the execution of the program is unusual. Unusual that the program gets executed one thread at a time despite threads running simultaneously. The output is the same when running on my virtual machine. Any possible reasons as to why this is happening?
Code
'''
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <pthread.h>
//shared variable
int SharedValue = 0;
//mutex lock
pthread_mutex_t lock;
//barrier
pthread_barrier_t barrier;
//which is an integer pointer to where each thread number is stored
void * SimpleThread(void * which) {
int num, val;
int thread_num = *(int *) which;
for(num = 0; num < 20; num ) {
#ifdef PTHREAD_SYNC
pthread_mutex_lock(&lock);
#endif
val = SharedValue;
printf("*** thread %d sees value %d\n", thread_num, val);
SharedValue = val 1;
#ifdef PTHREAD_SYNC
pthread_mutex_unlock(&lock);
#endif
}
//barrier here
#ifdef PTHREAD_SYNC
pthread_barrier_wait(&barrier);
#endif
val = SharedValue;
printf("Thread %d sees final value %d\n", thread_num, val);
}
/*** main thread ***/
//given two arguements program_name, threads to make
int main(int argc, char* argv[]) {
int i, threadsToMake, error;
//verify the user has given number of arguements required to run
if(argc != 2) {
printf("Please provide a number of threads to create.\n");
return 0;
}
//Verify arguements are within range - integer
int arguementLength = strlen(argv[1]);
for(i = 0; i <arguementLength; i ) {
if(!isdigit(argv[1][i])) {
printf("Arguement is not a number.\n");
return 0;
}
}
//convert arguement to integer
threadsToMake = atoi(argv[1]);
//Making an array of pthreads
pthread_t thread_array[threadsToMake];
//makingan array of thread_nums to pass to function
int thread_nums[threadsToMake];
//initialize barrier to the number of threads for program
pthread_barrier_init(&barrier, NULL, threadsToMake);
for(i = 0; i < threadsToMake; i ){
//store the thread numbers
thread_nums[i] = i;
//Generate that many threads
//Send threads to SimpleThread
error = pthread_create(&thread_array[i], NULL, SimpleThread, (void *) &thread_nums[i]);
if(error != 0){
printf("Problem creating thread %d", i);
return 0;
}
}
//join all threads
for(i = 0; i < threadsToMake; i ){
pthread_join(thread_array[i], NULL);
}
return 0;
}
'''
Unusual output for 2 threads
'''
*** thread 0 sees value 0
*** thread 0 sees value 1
*** thread 0 sees value 2
*** thread 0 sees value 3
*** thread 0 sees value 4
*** thread 0 sees value 5
*** thread 0 sees value 6
*** thread 0 sees value 7
*** thread 0 sees value 8
*** thread 0 sees value 9
*** thread 0 sees value 10
*** thread 0 sees value 11
*** thread 0 sees value 12
*** thread 0 sees value 13
*** thread 0 sees value 14
*** thread 0 sees value 15
*** thread 0 sees value 16
*** thread 0 sees value 17
*** thread 0 sees value 18
*** thread 0 sees value 19
*** thread 1 sees value 20
*** thread 1 sees value 21
*** thread 1 sees value 22
*** thread 1 sees value 23
*** thread 1 sees value 24
*** thread 1 sees value 25
*** thread 1 sees value 26
*** thread 1 sees value 27
*** thread 1 sees value 28
*** thread 1 sees value 29
*** thread 1 sees value 30
*** thread 1 sees value 31
*** thread 1 sees value 32
*** thread 1 sees value 33
*** thread 1 sees value 34
*** thread 1 sees value 35
*** thread 1 sees value 36
*** thread 1 sees value 37
*** thread 1 sees value 38
*** thread 1 sees value 39
Thread 1 sees final value 40
Thread 0 sees final value 40
'''
CodePudding user response:
In addition to the general considerations expressed by @Uriel.Gi, pthreads mutexes do not, in general, impose a fairness policy. That is, when multiple threads contend to acquire a mutex, it does not necessarily go to the one that has been waiting longest, nor do threads that have recently held the mutex get de-prioritized.
As a result, a tight loop where a mutex is acquired at the very top and relinquished at the very bottom is an anti-pattern. A thread running such a loop attempts to re-acquire the mutex immediately after releasing it, and there is a very good chance that it succeeds because it's already running when it releases the mutex, any other threads waiting on it are not, and the attempt to re-acquire comes so quickly that other threads don't have much chance to cut in. This commonly produces a situation where the threads each hog the mutex for an extended time, with switches between them being rare.
Generally speaking, such a problem is a symptom of poor design. There cannot be concurrent execution of a critical region, so if substantially all of several threads' executions are inside critical regions guarded by the same mutex, then what's the point of the threads?
CodePudding user response:
How do you know its not multi threading? It probably is multi threaded, but for some possible reasons it may not look like it. First, because the task is very small and thread creation requires some time the first thread may finish even before the second init is finished.
Second, its up to the thread scheduler to decide which thread should run in every moment, and here it may be possible that he decided to run one to finish and then the other.
If you really want to see it multi threading, use a bigger task, like computing all primes in certain range or count divisors of a large number.
Those are functions that require more computing, and there will be a noticeable difference between runtime for single thread apps to multi thread apps (if you divide the work between them).