Unix c program to calculate pi using threads - c

Been working on this assignment for class. Put this code together but its giving me several errors I'm not able to solve.
Code
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
//global variables
int N, T;
double vsum[T];
//pie function
void* pie_runner(void* arg)
{
double *limit_ptr = (double*) arg;
double j = *limit_ptr;
for(int i = (N/T)*j; i<=((N/T)*(j+1)-1); j++)
{
if(i %2 =0)
vsum[j] += 4/((2*j)*(2*j+1)*(2*j+2));
else
vsum[j] -= 4/((2*j)*(2*j+1)*(2*j+2));
}
pthread_exit(0);
}
int main(int argc, char **argv)
{
if(argc != 3) {
printf("Error: Must send it 2 parameters, you sent %s", argc);
exit(1);
}
N = atoi[1];
T = atoi[2];
if(N !> T) {
printf("Error: Number of terms must be greater then number of threads.");
exit(1);
}
for(int p=0; p<T; p++) //initialize array to 0
{
vsum[p] = 0;
}
double pie = 3;
//launch threads
pthread_t tids[T];
for(int i = 0; i<T; i++)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&tids[i], &attr, pie_runner, &i);
}
//wait for threads...
for(int k = 0; k<T; k++)
{
pthread_join(tids[k], NULL);
}
for(int x=0; x<T; x++)
{
pie += vsum[x];
}
printf("pi computed with %d terms in %s threads is %k\n", N, T, pie);
}
One of the problems I'm having is with the array up top. It needs to be a global variable but it keeps telling me it's not a constant, even when I declare it as such.
Any help is appreciated, with the rest of the code also.
**EDIT: After updating the code using the comments below, here is the new code. I have a few errors still there and would appreciate help dealing with them.
1) Warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] int j = (int)arg;
2)Warning: cast to pointer from integer of different size [Wint - to - pointer - cast] pthread_create(.......... , (void*)i);
NEW CODE:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
//global variables
int N, T;
double *vsum;
//pie function
void* pie_runner(void* arg)
{
long j = (long)arg;
//double *limit_ptr = (double*) arg;
//double j = *limit_ptr;
//for(int i = (j-1)*N/T; i < N*(j) /T; i++)
for(int i = (N/T)*(j-1); i < ((N/T)*(j)); i++)
{
if(i % 2 == 0){
vsum[j] += 4.0/((2*j)*(2*j+1)*(2*j+2));
//printf("vsum %lu = %f\n", j, vsum[j]);
}
else{
vsum[j] -= 4.0/((2*j)*(2*j+1)*(2*j+2));
//printf("vsum %lu = %f\n", j, vsum[j]);
}
}
pthread_exit(0);
}
int main(int argc, char **argv)
{
if(argc != 3) {
printf("Error: Must send it 2 parameters, you sent %d\n", argc-1);
exit(1);
}
N = atoi(argv[1]);
T = atoi(argv[2]);
vsum = malloc((T+1) * sizeof(*vsum));
if(vsum == NULL) {
fprintf(stderr, "Memory allocation problem\n");
exit(1);
}
if(N <= T) {
printf("Error: Number of terms must be greater then number of threads.\n");
exit(1);
}
for(int p=1; p<=T; p++) //initialize array to 0
{
vsum[p] = 0;
}
double pie = 3.0;
//launch threads
pthread_t tids[T+1];
for(long i = 1; i<=T; i++)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&tids[i], &attr, pie_runner, (void*)i);
}
//wait for threads...
for(int k = 1; k<=T; k++)
{
pthread_join(tids[k], NULL);
}
for(int x=1; x<=T; x++)
{
pie += vsum[x];
}
printf("pi computed with %d terms in %d threads is %.20f\n", N, T, pie);
//printf("pi computed with %d terms in %d threads is %20f\n", N, T, pie);
free(vsum);
}
Values not working:
./pie1 2 1
pi computed with 2 terms in 1 threads is 3.00000000000000000000
./pie1 3 1
pi computed with 3 terms in 1 threads is 3.16666666666666651864
./pie1 3 2
pi computed with 3 terms in 2 threads is 3.13333333333333330373
./pie1 4 2
pi computed with 4 terms in 2 threads is 3.00000000000000000000
./pie1 4 1
pi computed with 4 terms in 1 threads is 3.00000000000000000000
./pie1 4 3
pi computed with 4 terms in 3 threads is 3.14523809523809516620
./pie1 10 1
pi computed with 10 terms in 1 threads is 3.00000000000000000000
./pie1 10 2
pi computed with 10 terms in 2 threads is 3.13333333333333330373
./pie1 10 3
pi computed with 10 terms in 3 threads is 3.14523809523809516620
./pie1 10 4
pi computed with 10 terms in 4 threads is 3.00000000000000000000
./pie1 10 5
pi computed with 10 terms in 5 threads is 3.00000000000000000000
./pie1 10 6
pi computed with 10 terms in 6 threads is 3.14088134088134074418
./pie1 10 7
pi computed with 10 terms in 7 threads is 3.14207181707181693042
./pie1 10 8
pi computed with 10 terms in 8 threads is 3.14125482360776464574
./pie1 10 9
pi computed with 10 terms in 9 threads is 3.14183961892940200045
./pie1 11 2
pi computed with 11 terms in 2 threads is 3.13333333333333330373
./pie1 11 4
pi computed with 11 terms in 4 threads is 3.00000000000000000000

There are numerous problems with that code. Your specific problem is that, in C, variable length arrays (VLAs) are not permitted at file scope.
So, if you want that array to be dynamic, you will have to declare the pointer to it and allocate it yourself:
int N, T;
double *vsum;
and then, in main() after T has been set:
vsum = malloc (T * sizeof(*vsum));
if (vsum == NULL) {
fprintf (stderr, "Memory allocation problem\n");
exit (1);
}
remembering to free it before exiting (not technically required but good form anyway):
free (vsum);
Among the other problems:
1/ There is no !> operator in C, I suspect the line should be:
if (N > T) {
rather than:
if (N !> T) {
2/ To get the arguments from the command line, change:
N = atoi[1];
T = atoi[2];
into:
N = atoi(argv[1]);
T = atoi(argv[2]);
3/ The comparison operator is ==, not =, so you need to change:
if(i %2 =0)
into:
if (i % 2 == 0)
4/ Your error message about not having enough parameters needs to use %d rather than %s, as argc is an integral type:
printf ("Error: Must send it 2 parameters, you sent %d\n", argc-1);
Ditto for your calculation message at the end (and fixing the %k for the floating point value):
printf ("pi computed with %d terms in %d threads is %.20f\n", N, T, pie);
5/ You pass an integer pointer into your thread function but there are two problems with that.
The first is that you then extract it into a double j, which cannot be used as an array index. If it's an integer being passed in, it should be turned back into an integer.
The second is that there is no guarantee the new thread will extract the value (or even start running its code at all) before the main thread changes that value to start up another thread. You should probably just convert the integer to a void * directly rather than messing about with integer pointers.
To fix both those, use this when creating the thread:
pthread_create (&tids[i], &attr, pie_runner, (void*)i);
and this at the start of the thread function:
int j = (int) arg;
If you get warnings or experience problems with that, it's probably because your integers and pointers are not compatible sizes. In that case, you could try something like:
pthread_create (&tids[i], &attr, pie_runner, (void*)(intptr_t)i);
though I'm not sure that will work any better.
Alternatively (though it's a bit of a kludge), stick with your pointer solution and just make sure there's no possibility of race conditions (by passing a unique pointer per thread).
First, revert the thread function to receiving its value by a pointer:
int j = *((int*) arg);
Then, before you start creating threads, you need to create a thread integer array and, for each thread created, populate and pass the (address of the) correct index of that array:
int tvals[T]; // add this line.
for (int i = 0; i < T; i++) {
tvals[i] = i; // and this one.
pthread_attr_t attr;
pthread_attr_init (&attr);
pthread_create (&tids[i], &attr, pie_runner, &(tvals[i]));
}
That shouldn't be too onerous unless you have so many threads the estra array will be problematic. But, if you have that many threads, you're going to have far greater problems.
6/ Your loop in the thread incorrectly incremented j rather than i. Since this is the same area touched by the following section, I'll correct it there.
7/ The use of integers in what is predominantly a floating point calculation means that you have to arrange your calculations so that they don't truncate divisions, such as 10 / 4 -> 2 where it should be 2.5.
That means the loop in the thread function should be changed as follows (including incrementing i as in previous point):
for (int i = j*N/T; i <= N * (j+1) / T - 1; i++)
if(i % 2 == 0)
vsum[j] += 4.0/((2*j)*(2*j+1)*(2*j+2));
else
vsum[j] -= 4.0/((2*j)*(2*j+1)*(2*j+2));
With all those changes, you get a reasonably sensible result:
$ ./picalc 100 101
pi computed with 100 terms in 101 threads is 3.14159241097198238535

Two problems with that array: The first is that T is not a compile-time constant, which it needs to be if you're programming in C++. The second is that T is initialized to zero, meaning the array will have a size of zero and all indexing of the array will be out of bounds.
You need to allocate the array dynamically once you have read T and know the size. In C you use malloc for that, in C++ you should use std::vector instead.

Related

why is this c code causing a race condition?

I'm trying to count the number of prime numbers up to 10 million and I have to do it using multiple threads using Posix threads(so, that each thread computes a subset of 10 million). However, my code is not checking for the condition IsPrime. I'm thinking this is due to a race condition. If it is what can I do to ameliorate this issue?
I've tried using a global integer array with k elements but since k is not defined it won't let me declare that at the file scope.
I'm running my code using gcc -pthread:
/*
Program that spawns off "k" threads
k is read in at command line each thread will compute
a subset of the problem domain(check if the number is prime)
to compile: gcc -pthread lab5_part2.c -o lab5_part2
*/
#include <math.h>
#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <stdlib.h>
typedef int bool;
#define FALSE 0
#define TRUE 1
#define N 10000000 // 10 Million
int k; // global variable k willl hold the number of threads
int primeCount = 0; //it will hold the number of primes.
//returns whether num is prime
bool isPrime(long num) {
long limit = sqrt(num);
for(long i=2; i<=limit; i++) {
if(num % i == 0) {
return FALSE;
}
}
return TRUE;
}
//function to use with threads
void* getPrime(void* input){
//get the thread id
long id = (long) input;
printf("The thread id is: %ld \n", id);
//how many iterations each thread will have to do
int numOfIterations = N/k;
//check the last thread. to make sure is a whole number.
if(id == k-1){
numOfIterations = N - (numOfIterations * id);
}
long startingPoint = (id * numOfIterations);
long endPoint = (id + 1) * numOfIterations;
for(long i = startingPoint; i < endPoint; i +=2){
if(isPrime(i)){
primeCount ++;
}
}
//terminate calling thread.
pthread_exit(NULL);
}
int main(int argc, char** args) {
//get the num of threads from command line
k = atoi(args[1]);
//make sure is working
printf("Number of threads is: %d\n",k );
struct timespec start,end;
//start clock
clock_gettime(CLOCK_REALTIME,&start);
//create an array of threads to run
pthread_t* threads = malloc(k * sizeof(pthread_t));
for(int i = 0; i < k; i++){
pthread_create(&threads[i],NULL,getPrime,(void*)(long)i);
}
//wait for each thread to finish
int retval;
for(int i=0; i < k; i++){
int * result = NULL;
retval = pthread_join(threads[i],(void**)(&result));
}
//get the time time_spent
clock_gettime(CLOCK_REALTIME,&end);
double time_spent = (end.tv_sec - start.tv_sec) +
(end.tv_nsec - start.tv_nsec)/1000000000.0f;
printf("Time tasken: %f seconds\n", time_spent);
printf("%d primes found.\n", primeCount);
}
the current output I am getting: (using the 2 threads)
Number of threads is: 2
Time tasken: 0.038641 seconds
2 primes found.
The counter primeCount is modified by multiple threads, and therefore must be atomic. To fix this using the standard library (which is now supported by POSIX as well), you should #include <stdatomic.h>, declare primeCount as an atomic_int, and increment it with an atomic_fetch_add() or atomic_fetch_add_explicit().
Better yet, if you don’t care about the result until the end, each thread can store its own count in a separate variable, and the main thread can add all the counts together once the threads finish. You will need to create, in the main thread, an atomic counter per thread (so that updates don’t clobber other data in the same cache line), pass each thread a pointer to its output parameter, and then return the partial tally to the main thread through that pointer.
This looks like an exercise that you want to solve yourself, so I won’t write the code for you, but the approach to use would be to declare an array of counters like the array of thread IDs, and pass &counters[i] as the arg parameter of pthread_create() similarly to how you pass &threads[i]. Each thread would need its own counter. At the end of the thread procedure, you would write something like, atomic_store_explicit( (atomic_int*)arg, localTally, memory_order_relaxed );. This should be completely wait-free on all modern architectures.
You might also decide that it’s not worth going to that trouble to avoid a single atomic update per thread, declare primeCount as an atomic_int, and then atomic_fetch_add_explicit( &primeCount, localTally, memory_order_relaxed ); once before the thread procedure terminates.

Squaring numbers w/ multiple threads

I'm trying to write a program that squares numbers 1-10,000 by creating 8 threads and each thread will take turns squaring ONE NUMBER EACH. Meaning that one thread will square 1, another will square 2, etc until all threads square a number. Then one thread will square 9, etc, all the way to 10,000. My code is below:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pthread.h>
#include <sys/types.h>
#define NUMBER_OF_THREADS 8
#define START_NUMBER 1
#define END_NUMBER 10000
FILE *f;
void *sqrtfunc(void *tid) { //function for computing squares
int i;
for (i = START_NUMBER; i<= END_NUMBER; i++){
if ((i % NUMBER_OF_THREADS) == pthread_self()){ //if i%8 == thread id
fprintf(f, "%lu squared = %lu\n", i, i*i); //then that thread should do this
}
}
}
int main(){
//Do not modify starting here
struct timeval start_time, end_time;
gettimeofday(&start_time, 0);
long unsigned i;
f = fopen("./squared_numbers.txt", "w");
//Do not modify ending here
pthread_t mythreads[NUMBER_OF_THREADS]; //thread variable
long mystatus;
for (i = 0; i < NUMBER_OF_THREADS; i++){ //loop to create 8 threads
mystatus = pthread_create(&mythreads[i], NULL, sqrtfunc, (void *)i);
if (mystatus != 0){ //check if pthread_create worked
printf("pthread_create failed\n");
exit(-1);
}
}
for (i = 0; i < NUMBER_OF_THREADS; i++){
if(pthread_join(mythreads[i], NULL)){
printf("Thread failed\n");
}
}
exit(1);
//Do not modify starting here
fclose(f);
gettimeofday(&end_time, 0);
float elapsed = (end_time.tv_sec-start_time.tv_sec) * 1000.0f + \
(end_time.tv_usec-start_time.tv_usec) / 1000.0f;
printf("took %0.2f milliseconds\n", elapsed);
//Do not modify ending here
}
I am not sure where my error is. I create my 8 threads in main, and then depending on their thread id (tid), I want that thread to square a number. As of right now, nothing is being printed into the output file and I can't figure out why. Is my tid comparison not doing anything? Any tips are appreciated. Thanks guys.
First, you intentionally pass a parameter to each thread so it know which thread it is (from 0 to 7) That is good, but you then don't use it anymore inside the thread (this leads to one of the possible confussions you have)
Second, as you say in the explanation of how the algorithm should go, you say each thread must square a different set of numbers, but all of them do square the same set of numbers (indeed the whole set of numbers)
You have two approaches to this: Let each thread square the number, and go for the next, eight places further (so the algorithm is the one described in your explanation) or you give different sets (each 1250 consecutive numbers) and let each thread act on is own separate interval.
That said, you have to reconstruct your for loop to do one of two:
for (i = parameter; i < MAX; i += 8) ...
or
for (i = 1250*parameter; i < 1250*(parameter+1); i++) ...
that way, you'll get each thread run with a different set of input numbers.

Multithreading pthread errors

Im trying to create a multithreaded application in C for Linux with pthreads library that makes an approximation of pi using infinite series with N+1 terms.Variable N and T are passed from the command line. I am using the Nilakantha approximation formula for pi. N is the upper limit of the number sequence to sum and T would be the # of child threads that calculate that sum. For example if I run command "./pie 100 4". The parent thread will create 4 child threads indexed 0 to 3. I have a global variable called vsum that is a double array allocated dynamically using malloc to hold values. So with 4 threads and 100 as the upper bound. My progam should compute:
Thread 0 computes the partial sum for i going from 0 to 24 stored to an element vsum[0]
Thread 1 computes the partial sum for i going from 25 to 49 stored to an element vsum[1]
Thread 2 computes the partial sum for i going from 50 to 74 stored to an element vsum[2]
Thread 3 computes the partial sum for i going from 75 to 99 stored to an element vsum[3]
After each thread makes calculations. The main thread will compute the sum by adding together all numbers from vsum[0] to vsum[T-1].
Im just starting to learn about threads and processes. Any help or advice would be appreciated. Thank you.
Code I wrote so far:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
double *vsum;
int N, T;
void *PI(void *sum) //takes param sum and gets close to pi
{
int upper = (int)sum;
double pi = 0;
int k = 1;
for (int i = (N/T)*upper; i <= (N/T)*(upper+1)-1; i++)
{
pi += k*4/((2*i)*(2*i+1)*(2*i+2));
if(i = (N/T)*(upper+1)-1)
{
vsum[upper] = pi;
}
k++;
}
pthread_exit(0);
}
int main(int argc, char*argv[])
{
T = atoi(argv[2]);
N = atoi(argv[1]);
if (N<T)
{
fprintf(stderr, "Upper bound(N) < # of threads(T)\n");
return -1;
}
int pie = 0;
pthread_t tid[T]; //thread identifier
pthread_attr_t attr; //thread attributes
vsum = (double *)malloc(sizeof(double));//creates dyn arr
//Initialize vsum to [0,0...0]
for (int i = 0; i < T; i++){
{
vsum[i] = 0;
}
if(argc!=2) //command line does not give proper # of values
{
fprintf(stderr, "usage: commandline error <integer values>\n");
return -1;
}
if (atoi(argv[1]) <0) //if its is negative/sum error
{
fprintf(stderr, "%d must be >=0\n", atoi(argv[1]));
return -1;
}
//CREATE A LOOP THAT MAKES PARAM N #OF THREADS
pthread_attr_init(&attr);
for(int j =0; j < T;j++)
{
int from = (N/T)*j;
int to = (N/T)*(j+1)-1;
//CREATE ARRAY VSUM TO HOLD VALUES FOR PI APPROX.
pthread_create(&tid[j],&attr,PI,(void *)j);
printf("Thread %d computes the partial sum for i going from %d to %d stored to an element vsum[%d]\n", j, from, to, j);
}
//WAITS FOR THREADS TO FINISH
for(int j =0; j <T; i++)
{
pthread_join(tid[j], NULL);
}
//LOOP TO ADD ALL THE vsum array values to get pi approximation
for(int i = 0; i < T; i++)
{
pie += vsum[i];
}
pie = pie +3;
printf("pi computed with %d terms in %d threads is %d\n",N,T,pie);
vsum = realloc(vsum, 0);
pthread_exit(NULL);
return 0;
}
Here is the error I dont see that I get on my program: What am I missing here?
^
pie.c:102:1: error: expected declaration or statement at end of input
}
When I try to run my program I get the following:
./pie.c: line 6: double: command not found
./pie.c: line 7: int: command not found
./pie.c: line 8: int: command not found
./pie.c: line 10: syntax error near unexpected token `('
./pie.c: line 10: `void *PI(void *sum) //takes param sum and gets close to pi'
I haven't looked at logic of your code, but I see following programming errors.
Change
pthread_create(&tid[j],&attr,PI,j);
to
pthread_create(&tid[j],&attr,PI,(void *)j);
pthread_create() takes 4th param as void * which is passed to the thread function.
Also fix your thread function PI to use passed parameter as int like
void *PI(void *sum) //takes param sum and gets close to pi
{
int upper = (int)sum; //don't use `atoi` as passed param is int.
...
//your existing code
}
The 3rd error is for line
realloc(vsum, 0);
By passing 0 to re-allocate, you are effectively just freeing vsum, so you can just use free(vsum). If you indeed want to reallocate you should take the new allocated memory returned by the function something like vsum = realloc(vsum, 0);
The Syntax of pthread is
pthread_create(threadId, threadAttribute, callingMethodName, parameters of calling method);
Ex:
void printLetter( void *p)
{
int i=0;
char c=(char *)p;
while (i<10000)
{
printf("%c",c);
}
}
int main()
{
pthread_t thread_id;
char c='x';
pthread_create (&thread_id, NULL, &printLetter, &c);
pthread_join (thread_id, NULL);
return 0;
}
}

test "pthread_create" function behaviour

I am new in multi-threaded programming and I have a question about "pthread_create" behaviour
this is the code :
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NTHREADS 10
#define ARRAYSIZE 1000000
#define ITERATIONS ARRAYSIZE / NTHREADS
double sum=0.0, a[ARRAYSIZE];
pthread_mutex_t sum_mutex;
void *do_work(void *tid)
{
int i, k=0,start, *mytid, end;
double mysum=0.0;
mytid = (int *) tid;
start = (*mytid * ITERATIONS);
end = start + ITERATIONS;
printf ("Thread %d doing iterations %d to %d\n",*mytid,start,end-1);
for (i=start; i < end ; i++) {
a[i] = i * 1.0;
mysum = mysum + a[i];
}
sum = sum + mysum;
}
int main(int argc, char *argv[])
{
int i, start, tids[NTHREADS];
pthread_t threads[NTHREADS];
pthread_attr_t attr;
for (i=0; i<NTHREADS; i++) {
tids[i] = i;
pthread_create(&threads[i], NULL/*&attr*/, do_work, (void *) &tids[i]);
}
/* Wait for all threads to complete then print global sum */
/*
for (i=0; i<NTHREADS; i++) {
pthread_join(threads[i], NULL);
}*/
printf ("Done. Sum= %e \n", sum);
sum=0.0;
for (i=0;i<ARRAYSIZE;i++){
a[i] = i*1.0;
sum = sum + a[i]; }
printf("Check Sum= %e\n",sum);
}
the result of execution is :
Thread 1 doing iterations 100000 to 199999
Done. Sum= 0.000000e+00
Thread 0 doing iterations 0 to 99999
Thread 2 doing iterations 200000 to 299999
Thread 3 doing iterations 300000 to 399999
Thread 8 doing iterations 800000 to 899999
Thread 4 doing iterations 400000 to 499999
Thread 5 doing iterations 500000 to 599999
Thread 9 doing iterations 900000 to 999999
Thread 7 doing iterations 700000 to 799999
Thread 6 doing iterations 600000 to 699999
Check Sum= 8.299952e+11
all thread are created and the execution is not sequential (remove pthread_join), but the function do_work is executed in order and depend on thread. it means iterations 0 to 99999 are done by thread 0 and iterations 100000 to 199999 are done by thread 1 etc ...
the question is here why for example iterations 0 to 99999 is not done by thread 2 ?
This is because iteration range is calculated based on thread number from 0 to N in the following line:
start = (*mytid * ITERATIONS);
And you create and pass that number in a loop as such:
for (i=0; i<NTHREADS; i++) {
tids[i] = i;
...
In other words, 2 + N will never be 0 to perform iteration over 0 to 99999 when N is non-negative.
I think you are confused as to what threads are.
Think about each thread as its own program. If you run 10 programs at the same time, they will be running "simultaneously", i.e. instructions of these 10 programs will be interleaved, but within each program all instructions are executed in the deterministic order.
Same thing with threads. You define which numbers each thread will iterate over by passing the thread id argument when creating the thread.
You are sending the address of tids[i]th variable to thread i and printing based on it. In this case Nth thread will always print from N000000 till N999999 without any change in all the trial runs.
mytid = (int *) tid;
start = (*mytid * ITERATIONS);
end = start + ITERATIONS;
For thread 2, it would behave as,
mytid = (int *) tid; // *mytid = 2
start = ( 2 * ITERATIONS); // 2000000
end = ( 2 * ITERATIONS) + ITERATIONS; // 2999999
Thus printing 2000000 to 2999999. So you can't expect thread 2 to print 0 to 99999.
It is not wise to use global variables like sum, which are shared between threads, without any kind of locking mechanisms. They would bring unexpected results. Use of pthread_mutex here would solve this problem.

How to synchronize threads?

I used threads in this code. but when I execute this code in shell, some threads didn't print this line.
printf("\ti'm %dth thread:)", j);
printf("\t%c %d %d %d \n", arr[j].op, arr[j].byte, seq, no_file);
In addition, even some threads print this line twice. what happened to this process? And how to reorganize this code in order to threads print the line exactly once?
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
typedef struct {char op; int byte; int seq; int no_file; } ARRAY;
ARRAY *arr;
void *thread_operation(void *arg){
int j =*((int*)arg);
seq = arr[j].seq;
int no_file = arr[j].no_file;
printf("\ti'm %dth thread:)", j);
printf("\t%c %d %d %d \n", arr[j].op, arr[j].byte, seq, no_file);
}
int main()
{
int err, j, i = 10;
long int tid;
arr = (ARRAY*)malloc(sizeof(ARRAY) * i);
srand(time(NULL));
for (i = 0; i <= 10; i++){
arr[i].op = 'r';
arr[i].byte = (rand() % 10);
arr[i].seq = i;
arr[i].no_file = i + 10;
}
for(j = 0; j < 10; j++){
printf("creating %dth thread.....", j);
err = pthread_create(&tid, NULL, thread_operation, &j);
if(err != 0)
printf("%s\n", strerror(err));
printf("%dth done\n", j);
}
return 0;
}
This is result from my pc
creating 0th thread.....0th done
creating 1th thread..... i'm 0th thread:) r 9 0 10
1th done
creating 2th thread..... i'm 2th thread:) r 3 2 12
i'm 2th thread:) r 3 2 12
2th done
creating 3th thread..... i'm 3th thread:) r 6 3 13
3th done
creating 4th thread..... i'm 4th thread:) r 9 4 14
4th done
creating 5th thread..... i'm 5th thread:) r 3 5 15
5th done
creating 6th thread..... i'm 6th thread:) r 2 6 16
6th done
creating 7th thread..... i'm 7th thread:) r 2 7 17
7th done
creating 8th thread.....8th done
creating 9th thread..... i'm 8th thread:) r 6 8 18
9th done
i'm 9th thread:) r 8 9 19
i'm 9th thread:) r 8 9 19
You need to use mutexes ton avoid race conditions, and you also need to use pthread_join to synchronize all your threads before the process dies.
Mutexes allow you to stop some threads while one of them is executing an action using a shared ressource (see man pthread_mutex_lock, pthread_mutex_init)
pthread_join is essential in your code, because it forces your main thread to wait for the other threads you created, if you don't use it, you're not sure all threads will be finished when the main thread returns from the main.
The reason why some are printing out twice (such as thread number 9) is because you are passing a pointer to your loop variable as the input to the thread_operation.
for(j = 0; j < 10; j++){
err = pthread_create(&tid, NULL, thread_operation, &j);<---here
that &j is eventually dereferenced by thread_operation:
void *thread_operation(void *arg){
int j =*((int*)arg);<---here
but at this point the loop could have advanced and the value of j (in the thread operation) will be whatever j happens to be in the loop right now. The way to fix this is to not pass a pointer but the value of j to the thread constructor. Change your pthread_create to pass the value:
pthread_create(&tid, NULL, thread_operation, (void*) j);
and in your thread cast the value out of the thread argument:
int j =(int)arg;
Now technically this relies on the fact that int and void* are the same size when in general they are not. But this will work as long as you aren't using giant int values.
for all the other problems #Intrepidd is right about using pthread_join to make sure that the process doesn't exit before all your threads complete.
Using printf with incomplete lines between threads will usually not work. You may get the output completely mangled. Also the order in which lines appear on your screen will in general not be the execution order but the order the threads access the shared resource stdout.

Resources