I'm writing a program that performs gaussian elimination given an A and B matrix. I first grab divisor and multipliers, create pthreads which execute in gauss function which perform their operations on a single 'column'. Then I call main which generates new divisor and multipliers and passes back for another round of operations by the same threads. Using condition pthread vars to accomplish this.
The code hangs until I create a breakpoint which it then proceeds and finishes. Not sure what's holding it up. Could use some help.
#include <stdio.h>
#include <pthread.h>
//Need one mutex variable and two condition variables (one c var for
//communicating between threads, and one c var for communicating with main).
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t condM = PTHREAD_COND_INITIALIZER;
float arr[3][4] = {{2,-3,1, -22},{7,9,-3, 14},{6,7,2,91}};
float mults[3];
float divisor;
int num_items = 3;
void* gauss(void *mine)
{
int thread_count=0;
int x = *((int *)mine);
for(int i=0;i<num_items;i++)
{
/*do something*/
arr[i][x] = arr[i][x] / divisor;
for(int k=0;k<num_items;k++){
if(k!=i)
arr[k][x] -= mults[k] * arr[i][x];
}
/*lock || wait || signal*/
pthread_mutex_lock(&mut);
thread_count++;
if(thread_count < num_items)
pthread_cond_wait(&cond,&mut);
else
{
pthread_cond_signal(&condM);
pthread_cond_wait(&cond,&mut);
thread_count = 0;
}
pthread_mutex_unlock(&mut);
}
return NULL;
}
int main(int argc, const char * argv[]) {
int i, j;
pthread_t threadr[num_items+1]; /*thread id array */
int is[num_items+1];
printf("Test");
// /*input num items*/
// printf("input the number of items ");
// scanf("%d",&num_items);
//
// /*input A array*/
// printf("input A array\n");
// for(i=0;i<num_items;i++)
// for(j=0;j<num_items;j++)
// scanf("%f",&arr[i][j]);
//
// /*input B array*/
// printf("input B array\n");
// for(i=0;i<num_items;i++)
// scanf("%f",&arr[i][num_items]);
/*grab first divisor & multipliers*/
divisor = arr[0][0];
for(i=0;i<num_items;i++)
{
mults[i] = arr[i][0];
}
for(i=0;i<num_items+1;i++)
{
is[i]=i;
if(pthread_create(&threadr[i],NULL,gauss,(void *)&is[i]) != 0)
perror("Pthread_create fails");
}
for(i=1;i<num_items;i++)
{
pthread_mutex_lock(&mut);
pthread_cond_wait(&condM,&mut);
divisor = arr[i][i];
for(j=0;j<num_items;j++)
{
mults[j] = 1;
if(j != i)
mults[j] = arr[j][i];
}
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mut);
}
printf("The X values are:\n");
for(i=0;i<num_items; i++) {
printf("%0.3f \n", arr[i][num_items]);
}
/*wait for all threads*/
for(i=0;i<num_items+1; i++)
if (pthread_join(threadr[i],NULL) != 0)
perror("Pthread_join fails");
return 0;
}
You have a race condition (at least one), and your code does not use its condition variables correctly. You can probably fix the former by fixing the latter. Also, I suspect that you intend gauss()'s local variable thread_count to be shared, but variables with no linkage are not shared.
First, the race condition. Consider the main thread: it starts the three other threads, and then locks the mutex and waits for condition variable condM to be signaled. But suppose the threads all manage to signal condM before the main thread starts waiting? Condition variable operations are immediate -- any signals to condM that occur before main() is waiting on it are lost.
Now let's shift gears to talk about condition variables. As the Linux manual for pthread_cond_wait() puts it:
When using condition variables there is always a Boolean predicate involving shared variables associated with each condition wait that is true if the thread should proceed. Spurious wakeups from the pthread_cond_timedwait() or pthread_cond_wait() functions may occur. Since the return from pthread_cond_timedwait() or pthread_cond_wait() does not imply anything about the value of this predicate, the predicate should be re-evaluated upon such return.
In other words, condition variables are used to suspend thread operations pending a given condition becoming true. In abstract terms, that condition is always "it's ok for this thread to proceed", but that's realized in context-specific terms. Most importantly, the fact that a thread wakes from its wait never inherently communicates that the condition is true; it merely indicates that the newly-woken thread should check whether the condition is true. Generally, the thread should also check before waiting for the first time, as the condition may already be true.
In pseudocode, that looks like this:
Thread 1:
lock mutex;
loop
if is_ok_to_proceed then exit loop;
wait on condition variable;
end loop
// ... maybe do mutex-protected work ...
unlock mutex
Thread 2:
lock mutex
// ... maybe do mutex-protected work ...
is_ok_to_proceed = true;
signal condition variable;
unlock mutex
Generally speaking, there is also (mutex-protected) code somewhere else that make the CV predicate false, so that sometimes the threads indeed do execute their waits.
Now consider how that applies to the race condition in main(). How does main() know whether to wait on condM()? There needs to be a shared variable somewhere that answers that for it, and its wait must be conditioned on the value of that variable. Any thread that means to allow the main thread to proceed must both set the appropriate value for the variable and signal condM. The main thread itself should set the variable, too, as needed, to indicate that it is not ready, at that time, to proceed.
Of course, your other CV usage suffers from the same kind of problem, too.
Related
I am using two threads to update a global variable. In order to achieve mutual exclusion I am using the test_and_set function. But this code is going to deadlock at some random point during execiution.
Please help.
#include <stdio.h>
#include <pthread.h>
#include <stdatomic.h>
int a = 0;
atomic_int lock = 0;
int test_and_set(int *lock)
{
int l = *lock;
*lock = 1;
return l;
}
void *func(void * param)
{
for(int i = 0; i < 100000; i++)
{
while(test_and_set(&lock));
a++;
lock = 0;
}
}
int main()
{
pthread_t p1, p2;
pthread_create(&p1, NULL, func);
pthread_create(&p2, NULL, func);
pthread_join(p1, NULL);
pthread_join(p2, NULL);
printf("%d, %d\n", a, b);
return 0;
}
Yes, it will deadlock sooner or later.
This is how:
Thread A will "get the lock" and be ready to execute a++ and lock = 0;
Thread B takes over and executes l = *lock;. Since A has the lock l is now 1.
Thread A takes over and executes both a++ and lock = 0;. This sets the lock to zero.
Thread B takes over and executes *lock = 1; and returns l that has the value 1.
Now it's a deadlock. The value of lock is 1. Thread A return 1 from test_and_set and will stay in the while. Thread B will start reading the lock but will always get a 1. There is no thread that will set the lock to zero. Bang...
Likewise you can create a situation where both threads gets "the lock" at the same time.
Long story short: You can't implement a lock like that.
From https://en.wikipedia.org/wiki/Test-and-set:
In computer science, the test-and-set instruction is an instruction used to write 1 (set) to a memory location and return its old value as a single atomic (i.e., non-interruptible) operation.
You don't have "a single atomic operation". Therefore thread A above can execute step 3 between thread B executing step 2 and step 4.
If your processor has a test-and-set instruction, you can try with assembler code.
Note: In the "real" world, task switches do not happen aligned with C statements. A single C statement it typically realized as a number of machine instructions. A task switch can happen at any machine instruction. Still the principle is the same.
I haven't yet figured where your deadlock is occurring but this is not the proper way to implement a lock of data shared by threads. Suppose that lock is 0 and that both threads call test_and_set simultaneously. They will both see that lock is 0 and will both set it to 1. That 0 gets returned and so both threads think that they have the lock.
A mutex (short for "mutual exclusion") accomplishes what you're attempting here by ensuring that the fore-mentioned asynchronous mess can't happen.
When you call pthread_mutex_lock on a mutex, that function will not return until the calling thread has acquired the lock. That means that any other thread calling pthread_mutex_lock will block until the first thread releases the mutex by calling pthread_mutex_unlock.
Here's how you should use the mutex.
int a = 0;
pthread_mutex_t lock;
void *func(void * param)
{
for(int i = 0; i < 100000; i++)
{
pthread_mutex_lock(&lock):
a++;
pthread_mutex_unlock(&lock);
}
}
int main() {
pthread_t p1, p2;
pthread_mutex_init(&lock,NULL);
...
}
I'm trying to synchronize three pthreads using shared variables and mutex, such that they create the output: 123123123... However, all I can think of is using while loop as shown in the code below.
Is it possible to make the code more elegant, without making the threads sleep and using while loop?
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
static pthread_mutex_t cs_mutex;
char p;
int q;
void* print(void *pParam)
{
char c = *(char*)pParam;
int i;
for (i = 0; i < 100; i++)
{
while(p!=c) sleep(0.2);
pthread_mutex_lock(&cs_mutex);
printf("%c", c);
fflush(stdout);
q=(q+1)%4;
if(q==0)q=1;
p=q+48;
pthread_mutex_unlock(&cs_mutex);
}
return 0;
}
int main(void)
{
pthread_t hPrint1;
pthread_t hPrint2;
pthread_t hPrint3;
pthread_mutex_init(&cs_mutex, NULL);
char c1 = '1';
char c2 = '2';
char c3 = '3';
p=c1;
q=1;
pthread_create(&hPrint1, NULL, print, (void*)&c1);
pthread_create(&hPrint2, NULL, print, (void*)&c2);
pthread_create(&hPrint3, NULL, print, (void*)&c3);
getchar();
pthread_mutex_destroy(&cs_mutex);
return 0;
}
When multiple threads try to acquire the mutex at the same time, any one of them can acquire it. So, if the "wrong" thread acquires the mutex, it must yield, somehow, so that the correct thread gets the mutex. In OP's code, the sleep(0.2) attempts to do this. (It is a busy wait, and does not work as intended, because the unistd.h sleep() takes an integer number of seconds as a parameter.)
A better option would be to use a mutex, a condition variable, and the sequence index as a shared variable. In pseudocode, each thread would then do:
Function Thread(mynumber, mychar):
Lock mutex
Loop:
Wait on condition variable
If index >= limit:
Signal on condition variable
Unlock mutex
Return
Else
If (index % mynumber == 0):
Output mychar
Signal on condition variable
Else:
Broadcast on condition variable
End If
End Loop
End Function
The way to pass more than one variable to the thread function is very similar to how you passed the character. Instead of a char, you just use a structure. For example:
struct work {
int mynumber; /* Thread number: 0, 1, 2 */
int mychar; /* Character to output: '1', '2', '3' */
};
You can declare struct work w[3]; as a global variable or in your main(), and initialize it using e.g.
struct work w[3];
w[0].mynumber = 0; w[0].mychar = '1';
w[1].mynumber = 1; w[1].mychar = '2';
w[2].mynumber = 2; w[2].mychar = '3';
and refer to their address as say &(w[0]) (or equivalently just &w[0]).
In the thread function, you can use e.g.
void *worker(void *payload)
{
struct work *const w = payload;
/* w->mynumber is the number (0, 1, 2) of this thread,
w->mychar is the char ('1', '2', '3') to output */
Note that pthread_cond_signal() wakes up one thread already waiting on the condition variable, and pthread_cond_broadcast() wakes up all threads already waiting on the condition variable.
In the normal case, we only wake up one thread, to try and avoid the so-called thundering herd problem. It is not a real problem with just three threads, but I thought it is probably a good idea to introduce the concept here. Only if we find out the current thread is not the right one, do we wake up all the threads waiting on the condition variable.
If we only signaled on the condition variable, then it might be possible that two wrong threads would just alternate; that's why we really need that broadcast.
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?
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:
The various computational threads' writes to the shared result variable
The main thread's reads of the result variable
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:
the result variable in which your threads deposit their terms must be a global. Threads do not have access to the local variables of the function from which they are launched.
the signature of your term() function is incorrect for a thread start function. The argument must be of type void *.
thread start functions are no different from other functions in that their local variables are accessible only for the duration of the function execution. In particular, returning a pointer to a local variable cannot do anything useful, as any attempt to later dereference such a pointer produces undefined behavior.
I'm not going to write your homework for you, but here's an approach that can work:
The main thread initializes a mutex and two semaphores, the latter with initial values zero.
The main thread launches all the computational threads. Although it's ugly, you can feed them their numeric arguments by casting those to void *, and then casting them back in the term() function (since its argument should be a void *).
The main thread then loops. At each iteration, it
waits for semaphore 1 (sem_wait())
adds the value of the global result variable to a running total
posts to semaphore 2 (sem_post())
if as many iterations have been performed as there are threads, breaks from the loop
Meanwhile, each computational thread does this:
Computes the value of the appropriate term
locks the mutex
stores the term value in the global result variable
posts to semaphore 1
waits for semaphore 2
unlocks the mutex
Update:
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:
Ready to receive a value from a computational thread, and
Ready for the main thread to read.
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:
The main thread initializes a mutex and two condition variables, and sets result to -1.
The main thread launches all the computational threads. Although it's ugly, you can feed them their numeric arguments by casting those to void *, and then casting them back in the term() function (since its argument should be a void *).
The main thread locks the mutex
The main thread then loops. At each iteration, it
tests whether result is non-negative. If so, it
adds the value of result variable to a running total
if as many terms have been added as there are threads, breaks from the loop
sets result to -1.
signals condition variable 1
waits on condition variable 2
Having broken from the loop, the main thread unlocks the mutex
Meanwhile, each computational thread does this:
Computes its term
Locks the mutex
Loops:
Checks the value of result. If it is less than zero then breaks from the loop
waits on condition variable 1
Having broken from the loop, sets result to the computed term
signals condition variable 2
unlocks the mutex
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
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.
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. }
I have a problem with multithreading, since I'm new to this topic. Code below is code I've been given from my University. It was in few versions, and I understood most of them. But I don't really understand the nready.nready variable and all this thread condition. Can anyone describe how those two work here? And why can't I just synchronise work of threads via mutex?
#include "unpipc.h"
#define MAXNITEMS 1000000
#define MAXNTHREADS 100
/* globals shared by threads */
int nitems; /* read-only by producer and consumer */
int buff[MAXNITEMS];
struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
int nput;
int nval;
int nready;
} nready = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER };
void *produce(void *), *consume(void *);
/* include main */
int
main(int argc, char **argv)
{
int i, nthreads, count[MAXNTHREADS];
pthread_t tid_produce[MAXNTHREADS], tid_consume;
if (argc != 3)
err_quit("usage: prodcons5 <#items> <#threads>");
nitems = min(atoi(argv[1]), MAXNITEMS);
nthreads = min(atoi(argv[2]), MAXNTHREADS);
Set_concurrency(nthreads + 1);
/* 4create all producers and one consumer */
for (i = 0; i < nthreads; i++) {
count[i] = 0;
Pthread_create(&tid_produce[i], NULL, produce, &count[i]);
}
Pthread_create(&tid_consume, NULL, consume, NULL);
/* wait for all producers and the consumer */
for (i = 0; i < nthreads; i++) {
Pthread_join(tid_produce[i], NULL);
printf("count[%d] = %d\n", i, count[i]);
}
Pthread_join(tid_consume, NULL);
exit(0);
}
/* end main */
void *
produce(void *arg)
{
for ( ; ; ) {
Pthread_mutex_lock(&nready.mutex);
if (nready.nput >= nitems) {
Pthread_mutex_unlock(&nready.mutex);
return(NULL); /* array is full, we're done */
}
buff[nready.nput] = nready.nval;
nready.nput++;
nready.nval++;
nready.nready++;
Pthread_cond_signal(&nready.cond);
Pthread_mutex_unlock(&nready.mutex);
*((int *) arg) += 1;
}
}
/* include consume */
void *
consume(void *arg)
{
int i;
for (i = 0; i < nitems; i++) {
Pthread_mutex_lock(&nready.mutex);
while (nready.nready == 0)
Pthread_cond_wait(&nready.cond, &nready.mutex);
nready.nready--;
Pthread_mutex_unlock(&nready.mutex);
if (buff[i] != i)
printf("buff[%d] = %d\n", i, buff[i]);
}
return(NULL);
}
/* end consume */
pthread_mutex_lock(&nready.mutex);
while (nready.nready == 0)
pthread_cond_wait(&nready.cond, &nready.mutex);
nready.nready--;
pthread_mutex_unlock(&nready.mutex);
The whole point of this structure is to guarantee that the condition (nready.nready == 0) is still true when you execute the corresponding action (nready.nready--) or - if the condition is not satisfied - to wait until it is without using CPU time.
You could use a mutex only, to check that the condition is correct and to perform the corresponding action atomically. But if the condition is not satisfied, you wouldn't know what to do. Wait? Until when? Check it again? Release the mutex and re-check immediately after? That would be wasting CPU time...
pthread_cond_signal() and pthread_cond_wait() are here to solve this problem. You should check their man pages.
Briefly, what pthread_cond_wait does, is it puts the calling thread to sleep and release the mutex in an atomic way until it's signaled. So this is a blocking function. The thread can then be re-scheduled by calling signal or broadcast from a different thread. When the thread is signaled, it grabs the mutex again and exit the wait() function.
Ath this point you know that
your condition is true and
you hold the mutex.
So you can do whatever you need to do with your data.
Be careful though, you shouldn't call wait, if you're not sure that another thread will signal. This is a very common source of deadlocks.
When a thread received a signal, it's put on the list of threads that are ready to be scheduled. By the time the thread is actually executed, your condition (i.e. nread.nready == 0) may be false again. Hence the while (to recheck if the thread is waked).
"But I don't really understand the nready.nready variable"
this results from the struct instance being named 'nready' and there
is a field within the struct named 'nready'
IMO: a very poor design to have two different objects being given the same name
the nready field of the nready struct seems to be keeping track of the number of
items that have been 'produced'
1) The nready filed of struct nready is used to tack how many tasks are ready to consume, i.e., the remaining tasks in array buff. The nready.nready++; statement is only executed when producers put one new item in array buff, and the nready.nready--; is only executed when consume gets item out of buff. With is variable, programmer can always track how many tasks are there left to process.
2)
pthread_mutex_lock(&nready.mutex);
while (nready.nready == 0)
pthread_cond_wait(&nready.cond, &nready.mutex);
nready.nready--;
pthread_mutex_unlock(&nready.mutex);
The statements above are common condition variable usage. You can check
POSIX Threads Programming and Condition Variables for more about condition variables.
Why can't use mutex only? You can poll a mutex lock again and again. Obviously, it is CPU time consuming and may be hugely affect system performance. Instead, you want the consume to wait in sleep when there is no more items in buff, and to be awaken when producer puts new item in buff. The condition variable is acting as this role here. When there is no items (nready.nready==0), pthread_cond_wait() function puts the current thread into sleep, save the precious cpu time. When new items are arriving, Pthread_cond_signal() awakes the consumer.
I am working on a project with a user defined number of threads I am using 7 at the moment. I have a while loop that runs in each thread but I need all of the threads to wait for each other at the end of the while loop. The tricky thing is that some of the threads do not all end on the same number of times through the loop.
void *entryFunc(void *param)
{
int *i = (int *)param;
int nextPrime;
int p = latestPrime;
while(latestPrime < testLim)
{
sem_wait(&sem);
nextPrime = findNextPrime(latestPrime);
if(nextPrime != -1)
{
latestPrime = nextPrime;
p = latestPrime;
}
else
{
sem_post(&sem);
break;
}
sem_post(&sem);
if(p < 46341)
{
incrementNotPrimes(p);
}
/*
sem_wait(&sem2);
doneCount++;
sem_post(&sem2);
while(go != 1);
sem_wait(&sem2);
doneCount--;
//sem_post(&sem3);
sem_post(&sem2);
*/
}
return NULL;
}
where the chunk of code is commented out is part of my last attempt at solving this problem. That is where the functions all need to wait for each other. I have a feeling I am missing something simple.
If your problem is that on each thread, the while loop has a different numbers of iterations and some threads never reach the synchronization point after exiting the loop, you could use a barrier. Check here for an example.
However you need to decrease the number of threads at the barrier after you exit each thread. Waiting at the barrier will end after count number of threads reached that point.
So you need to update the barrier object each time a thread finishes. And make sure you do this atomically.
As I mentioned in the comments, you should use a barrier instead of a semaphore for this kind of situation, as it should be simpler to implement (barriers have been designed exactly to solve that problem). However, you may still use a semaphore with a little bit of arithmetic
arithmetic: your goal is to have all thread execute the same code path, but somehow the last thread to finish its task should wake all the other threads up. One way to achieve that is to have at the end of the function an atomic counter which each thread would decrement, and if the counter reaches 0, the thread simply calls as many time sem_post as necessary to release all the waiting threads, instead of issuing a sem_wait as the others.
A second method, this time using only a semaphore, is also possible. Since we cannot differentiate the last thread for the others, all the threads must do the same operations with the semaphore, ie try to release everyone, but also wait for the last one. So the idea is to initialize the semaphore to (1-n)*(n+1), so that each of the n-1 first threads would fail at waking up their friends with n+1 calls to sem_post, but still work toward getting the semaphore at exactly 0. Then the last thread would do the same, pushing the semaphore value to n+1, thus releasing the locked threads, and leaving room for it to also perform its sem_wait and be released immediately.
void *entryFunc(void *param)
{
int *i = (int *)param;
int nextPrime;
int p = latestPrime, j;
while(latestPrime < testLim){
nextPrime = findNextPrime(latestPrime);
if(nextPrime != -1)
{
latestPrime = nextPrime;
p = latestPrime;
}
if(p < 46341)
{
incrementNotPrimes(p);
}
}
for (j=0;j<=THREAD_COUNT;j++)
sem_post(&sem);
sem_wait(&sem);
return NULL;
}
The problem with this approach is that it doesn't deal with how the semaphore should be reset in between uses (if your program needs to repeat this mechanism, it will need to reset the semaphore value, since it will end up being 1 after this code has been executed successfully).