Reputation: 101
I've got to write a program that counts series of first 10 terms (sorry for my language, this is the first time that I'm talking about math in english) given by formula (x^i)/i!. So, basically it's trivial. BUT, there's some special requirements. Every single term got to be counted by seperated thread, each of them working concurrent. Then all of them got to save results to common variable named result. After that they have to be added by main thread, which will display final result. All of it using pthreads and mutexes.
That's where I have a problem. I was thinking about using table to store results, but I was told by teacher, that it's not correct solution, cause then I don't have to use mutexes. Any ideas what to do and how to synchronize it? I'm completely new to pthread and mutex.
Here's what I got till now. I'm still working on it, so it's not working at the moment, it's just a scheme of a program, where I want to add mutexes. I hope it's not all wrong. ;p
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>
int number = 0;
float result = 0;
pthread_mutex_t term_lock;
pthread_mutex_t main_lock;
int save = 0; //condition variable
int factorial(int x) {
if(x==0 || x==1)
return 1;
return factorial(x-1)*x;
}
void *term(void *value) {
int x = *(int *)value;
float w;
if(save == 0) {
pthread_mutex_lock(&term_lock);
w = pow(x, number)/factorial(number);
result = w;
printf("%d term of series with x: %d is: %f\n", number, x, w);
number++;
save = 1;
pthread_mutex_unlock(&term_lock);
}
return NULL;
}
int main(void) {
int x, i, err = 0;
float final = 0;
pthread_t threads[10];
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
printf("Get X: \n");
scanf("%d", &x);
for(i=0; i<10; i++)
{
err = pthread_create(&threads[i], &attr, (void *)term, &x);
if(err) {
printf("Error creating threads.\n");
exit(-1);
}
}
i = 0;
while (number <= 10) {
//printf("While Result: %f, final %f\n", result, final); - shows that it's infinite loop
if(save) {
pthread_mutex_lock(&main_lock);
final = final + result;
save = 0;
pthread_mutex_unlock(&main_lock);
printf("If Result: %f, final %f\n", result, final); //final == last result
}
}
return 0;
}
EDIT: If it's not clear - I need help with solution how to store results of all threads in common variable and synchronizing it.
EDIT2: Possible solution - global variable result
shared by all threads. Returned to main thread, it would be added to some local variable, so then I could just overwrite it's value with result from another thread. Of course it will require some synchronization, so another thread won't overwrite it before I add it in main thread. What do you think?
EDIT3: I've updated code with what I have right now. Output is giving me me values of 8-9 terms (printf in term), then program is still working, showing nothing. Commented printf showed me, that while loop is infinite. Also local variable final has just last value of result. What am I doing wrong?
Upvotes: 1
Views: 2627
Reputation: 181734
It's rather contrived that the main thread should be the one to add the terms, but the individual threads must all write their results to the same variable. I would ordinarily expect each thread to add its own term to the result (which does require mutex), or possibly to put its result in an array (as you suggested), or to add it to a shared queue (which would require mutex), or even to write it to a pipe. Nevertheless, it can be done your teacher's way.
One of the key problems to solve is that you have to distinctly different operations that you need to synchronize:
You cannot use just a single synchronization construct because you cannot that way distinguish between the computational threads and the main thread. One way to approach this would be to synchronize the computational threads' writes via a mutex, as required, and to synchronize those vs. the main thread's reads via semaphores or condition variables. You could also do it with one or more additional mutexes, but not cleanly.
Additional notes:
term()
function is incorrect for a thread start function. The argument must be of type void *
.I'm not going to write your homework for you, but here's an approach that can work:
void *
, and then casting them back in the term()
function (since its argument should be a void *
).sem_wait()
)result
variable to a running totalsem_post()
)Meanwhile, each computational thread does this:
result
variableUpdate:
To use condition variables for this job, it is essential to identify which shared state is being protected by those condition variables, as one must always protect against waking spurriously from a wait on a condition variable.
In this case, it seems natural that the shared state in question would involve the global result
variable in which the computational threads return their results. There are really two general, mutually exclusive states of that variable:
The computational threads need to wait for the first state, and the main thread needs to wait (repeatedly) for the second. Since there are two different conditions that threads will need to wait on, you need two condition variables. Here's an alternative approach using these ideas:
result
to -1
.void *
, and then casting them back in the term()
function (since its argument should be a void *
).result
is non-negative. If so, it
result
variable to a running totalresult
to -1
.Meanwhile, each computational thread does this:
result
. If it is less than zero then breaks from the loopresult
to the computed termUpvotes: 1
Reputation: 28931
If result is to be a single variable, then one solution is to use an array of 20 mutexes: aMutex[20];. Main locks all 20 mutexes then starts the pthreads. Each pthread[i] computes a local term, waits for aMutex[i], stores it's value into result, then unlocks aMutex[10+i]. In main() for(i = 0; i < 20; i++){ unlock aMutex[i] to allow pthread[i] to store its value into result, then wait for aMutex[10+i] to know that result is updated, then add result to a sum. }
Upvotes: 0
Reputation: 23
Here is my solution to your problem:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>
int number=0;
float result[10];
pthread_mutex_t lock;
int factorial(int x) {
if(x==0 || x==1)
return 1;
return factorial(x-1)*x;
}
void *term(void *value) {
int x = *(int *)value;
float w;
pthread_mutex_lock(&lock);
w = pow(x, number)/factorial(number);
printf("%d term of series with x: %d is: %f\n", number, x, w);
result[number] = w;
number++;
pthread_mutex_unlock(&lock);
return NULL;
}
int main(void) {
int x, i, err;
pthread_t threads[10];
printf("Get X: \n");
scanf("%d", &x);
for(i=0; i<=9; i++)
{
err = pthread_create(&threads[i], NULL, term, &x);
if(err) {
printf("Error creating threads.\n");
exit(-1);
}
}
for(i = 0; i < 10; i++)
{
pthread_join(threads[i], NULL);
}
i = 0;
for(i=0; i<=9; i++)
{
printf("%f\n", result[i]);
}
return 0;
}
This code creates a global mutex pthread_mutex_t lock
that (in this case) makes sure that same code is not executed by anyone at the same time: basically when one thread executes pthread_mutex_lock(&lock)
, it forbids any other thread
from executing that part of the code until the "original" thread executes pthread_mutex_unlock(&lock)
.
The other important part is pthread_join
: what this does is force the main thread to wait for the execution of every other thread created; this way, float result[10]
is written before actually being worked on in the main thread (in this case, the last print instruction).
Other than that, I fixed a couple of bugs in your code that other users pointed out.
Upvotes: 0
Reputation: 14718
The number
is shared between all the threads, so you will need to protect that with a mutex (which is probably what your teacher is wanting to see)
pthread_mutex_t number_mutex;
pthread_mutex_t result_mutex;
int number = 0;
int result = 0;
void *term(int x) {
float w;
// Critical zone, make sure only one thread updates `number`
pthread_mutex_lock(&number_mutex);
int mynumber = number++;
pthread_mutex_unlock(&number_mutex);
// end of critical zone
w = pow(x, mynumber)/factorial(mynumber);
printf("%d term of series with x: %d is: %f\n", mynumber, x, w);
// Critical zone, make sure only one thread updates `result`
pthread_mutex_lock(&result_mutex);
result += w;
pthread_mutex_unlock(&result_mutex);
// end of critical zone
return (void *)0;
}
You should also remove the DETACHED state and do a thread-join at the end of your main program before printing out the result
Upvotes: 0