I'm trying to get pthread to output a variable declared in a for loop:
pthread_t pthread[10];
void * count(void* argv){
int index = *(int*)argv;
printf("%d", index);
pthread_exit(NULL);
}
int main() {
for (int i = 0; i < 10; ++i) {
pthread_create(&pthread[i], NULL, count,(void*)&i);
}
return 0;
}
Output I thought:
0123456789 (or not in order, but all 10 number)
What I got:
123456789
Why 0 is not in here?
One problem is that your main() thread exits without waiting for the child threads to finish, which means the child threads may not have time to finish (or potentially even begin) their execution before the process is terminated.
To avoid that problem, you need to call pthread_join() on all of your threads before main() exits, like this:
int main() {
for (int i = 0; i < 10; ++i) {
pthread_create(&pthread[i], NULL, count,(void*)&i);
}
for (int i = 0; i < 10; ++i) {
pthread_join(pthread[i], NULL); // won't return until thread has exited
}
return 0;
}
The other problem, as mentioned by 500 in the comments, is that you are passing a pointer to i to the child threads, which they then dereference, and since i is being modified in the main thread's loop, it's undefined behavior what value the child threads will read from that pointer. One way to avoid this is to give each thread its own separate (non-changing) integer to read:
int values[10];
for (int i = 0; i < 10; ++i) {
values[i] = i;
pthread_create(&pthread[i], NULL, count,(void*)&values[i]);
}
Related
I have had a problem threads for a long time. This code is supposed to have a worker thread increment the value of a shared integer while the main thread prints it out. However, I am not getting my expected output.
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
pthread_mutex_t lock;
int shared_data = 0; //shared data
// Often shared data is more complex than just an int.
void* thread_function(void* arg)
{
int i;
for (i = 0; i < 10; ++i)
{
// Access the shared data here.
pthread_mutex_lock(&lock);
shared_data++;
pthread_mutex_unlock(&lock);
}
return NULL;
}
int main(void)
{
pthread_t thread;
int i;
void* exit_status;
// Initialize the mutex before trying to use it.
pthread_mutex_init(&lock, NULL);
pthread_create(&thread, NULL, thread_function, NULL);
// Try to use the shared data.
for (i = 0; i < 10; ++i)
{
sleep(1);
pthread_mutex_lock(&lock);
printf ("\r for i= %d Shared integer 's value = %d\n", i, shared_data);
pthread_mutex_unlock(&lock);
}
printf("\n");
pthread_join(thread, &exit_status);
// Clean up the mutex when we are finished with it.
pthread_mutex_destroy(&lock);
return 0;
}
Here is what I expect:
for i=0 Shared Integer 's value = 0
for i=1 Shared Integer 's value = 1
for i=3 Shared Integer 's value = 2
...
for i=10 Shared Integer 's value =10
but the result is:
for i=0 Shared Integer 's value = 0
for i=1 Shared Integer 's value = 10
for i=3 Shared Integer 's value = 10
...
for i=10 Shared Integer 's value =10
so how can i resoleve this?
The main thread and your worker thread are running concurrently. That is, getting those for loops to coincide with each other perfectly is nearly impossible without extra synchronization.
Your output is exactly what you should expect. The time taken to spawn the thread allows the main thread to print before the other thread changes the shared data. Then, the print takes so long that the other thread completely finishes with its loop and increments the shared data to 10 before the main thread can get to its second iteration.
In a perfect world, this little hack using condition variables will get you what you want:
EDIT: condition variables were a bad idea for this. Here is working version that uses pseudo atomic variables and doesn't contain UB :) :
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
pthread_mutex_t want_incr_mut;
pthread_mutex_t done_incr_mut;
int want_incr = 0;
int done_incr = 0;
int shared_data = 0; //shared data
// Not using atomics, so...
void wait_for_want_increment()
{
while (1)
{
pthread_mutex_lock(&want_incr_mut);
if (want_incr)
{
pthread_mutex_unlock(&want_incr_mut);
return;
}
pthread_mutex_unlock(&want_incr_mut);
}
}
void wait_for_done_incrementing()
{
while (1)
{
pthread_mutex_lock(&done_incr_mut);
if (done_incr)
{
pthread_mutex_unlock(&done_incr_mut);
return;
}
pthread_mutex_unlock(&done_incr_mut);
}
}
void done_incrementing()
{
pthread_mutex_lock(&done_incr_mut);
done_incr = 1;
pthread_mutex_lock(&want_incr_mut);
want_incr = 0;
pthread_mutex_unlock(&want_incr_mut);
pthread_mutex_unlock(&done_incr_mut);
}
void want_increment()
{
pthread_mutex_lock(&want_incr_mut);
want_incr = 1;
pthread_mutex_lock(&done_incr_mut);
done_incr = 0;
pthread_mutex_unlock(&done_incr_mut);
pthread_mutex_unlock(&want_incr_mut);
}
// Often shared data is more complex than just an int.
void* thread_function(void* arg)
{
int i;
for (i = 0; i < 10; ++i)
{
wait_for_want_increment();
// Access the shared data here.
shared_data++;
done_incrementing();
}
return NULL;
}
int main(void)
{
pthread_t thread;
int i;
void* exit_status;
// Initialize the mutex before trying to use it.
pthread_mutex_init(&want_incr_mut, NULL);
pthread_mutex_init(&done_incr_mut, NULL);
pthread_create(&thread, NULL, thread_function, NULL);
// Try to use the shared data.
for (i = 0; i <= 10; ++i)
{
printf("\r for i= %d Shared integer 's value = %d\n", i, shared_data);
if (i == 10) break;
want_increment();
wait_for_done_incrementing();
}
printf("\n");
pthread_join(thread, &exit_status);
// Clean up the mutexes when we are finished with them.
pthread_mutex_destroy(&want_incr_mut);
pthread_mutex_destroy(&done_incr_mut);
return 0;
}
Here, we just tell the worker that we want an increment and wait for him to say he is done before we continue. Meanwhile, the worker waits for us to want an increment and tells us when he is done.
I also changed the main loop to go to ten because that is what I think you want.
Here is my output:
for i= 0 Shared integer 's value = 0
for i= 1 Shared integer 's value = 1
for i= 2 Shared integer 's value = 2
for i= 3 Shared integer 's value = 3
for i= 4 Shared integer 's value = 4
for i= 5 Shared integer 's value = 5
for i= 6 Shared integer 's value = 6
for i= 7 Shared integer 's value = 7
for i= 8 Shared integer 's value = 8
for i= 9 Shared integer 's value = 9
for i= 10 Shared integer 's value = 10
I have to find the biggest value in an array of a 1000 numbers with 10 child processes (so that every one of them only checks a hundred values), and the parent only has to collect the data.
I'm already done with the whole thing, but I'm stuck at reading the values.
Here's the code:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main(){
int array[1000];
int i, j;
int pids[10];
int searchminindex;
int searchmaxindex;
int maxindex;
srand(time(NULL));
//fill up array with random numbers
for(i = 0; i < 1000; i++)
{
tomb[i] = random() % 5000;
}
//create 10 child processes
for (i = 0; i < 10; i++) {
if ((pids[i] = fork()) < 0) {
perror("fork");
abort();
}
else if (pids[i] == 0) {
searchminindex = i * 100;
searchmaxindex = (i+1) * 100;
//finding the biggest value
maxindex = searchminindex;
for(j = searchminindex+1; j < maxindex; j++) {
if( array[maxindex] < array[j])
maxindex = j;
}
}
}
for(i = 0; i < 10; i++){
//here's where I'd read the return values of the subarrays
}
return 0;
}
I've tried using pipes and also using WEXITSTATUS, but I'm really confused and don't know where to close one end of the pipe and things like that, and with WEXITSTATUS I'm completely lost.
Any way you could help?
You need to test the pid returned from fork, and branch your code so your main process doesn't act like a child, and so that your children don't spawn children of their own. Once that's taken care of...
An alternative to mmap or setting up shared memory at all is to use WEXITSTATUS. According to the man page, it'll only return the least significant 8 bits, so if your return values can be greater than 127, this is likely not your best option. Can be made to work up to 255, but be careful about signedness of char, it's not standard.
int returned_values[10];
for(int i = 0; i < 10; ++i)
{
int status;
wait(&status);
if(WIFEXITED(status))
returned_values[i] = WEXITSTATUS(status);
else {
//Do something more meaningful here
//This means a child received a signal, or any of the other ways wait returns other than a child exiting.
--i;
}
You need to test the pid returned from fork, and branch your code so your main process doesn't act like a child, and so that your children don't spawn children of their own. Once that's taken care of...
Sharing memory between forked processes is explained well here
I would use mmap to create shared memory between the processes, you'll need to specify for each process where to put it's result, then use wait to determine when all children have exited, and a good program would evaluate the exit status and inform the user if any child exited abnormally.
Don't forget to clean up the shared memory before the parent exits.
I wrote this c-program :
int counter = 0;
void* increment()
{
int maxI = 10000;
int i;
for (i = 0; i < maxI; ++i) { counter++; }
}
int main()
{
pthread_t thread1_id;
pthread_t thread2_id;
pthread_create (&thread1_id,NULL,&increment,NULL);
pthread_create (&thread2_id,NULL,&increment,NULL);
pthread_join (thread1_id,NULL);
pthread_join (thread2_id,NULL);
printf("counter = %d\n",counter);
return 0;
}
As a result I get : counter = 10000
why is that ? I would have expected something much bigger instead as I am using two threads, how can I correct it
PS : I am aware that there will be a race condition!
edit : volatile int counter seems to solve the problem :)
Predicting what code with bugs will do is extremely difficult. Most likely, the compiler is optimizing your increment function to keep counter in a register. But you'd have to look at the generated assembly code to be sure.
The task is to have 5 threads present at the same time, and the user assigns each a burst time. Then a round robin algorithm with a quantum of 2 is used to schedule the threads. For example, if I run the program with
$ ./m 1 2 3 4 5
The output should be
A 1
B 2
C 2
D 2
E 2
C 1
D 2
E 2
E 1
But for now my output shows only
A 1
B 2
C 2
Since the program errs where one thread does not end for the time being, I think the problem is that this thread cannot unlock to let the next thread grab the lock. My sleep() does not work, either. But I have no idea how to modify my code in order to fix them. My code is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
double times[5];
char process[] = {'A', 'B', 'C', 'D', 'E'};
int turn = 0;
void StartNext(int tid) //choose the next thread to run
{
int i;
for(i = (tid + 1) % 5; times[i] == 0; i = (i + 1) % 5)
if(i == tid) //if every thread has finished
return;
turn = i;
}
void *Run(void *tid) //the thread function
{
int i = (int)tid;
while(times[i] != 0)
{
while(turn != i); //busy waiting till it is its turn
if(times[i] > 2)
{
printf("%c 2\n", process[i]);
sleep(2); //sleep is to simulate the actual running time
times[i] -= 2;
}
else if(times[i] > 0 && times[i] <= 2) //this thread will have finished after this turn
{
printf("%c %lf\n", process[i], times[i]);
sleep(times[i]);
times[i] = 0;
}
StartNext(i); //choose the next thread to run
}
pthread_exit(0);
}
int main(int argc, char **argv)
{
pthread_t threads[5];
int i, status;
if(argc == 6)
{
for(i = 0; i < 5; i++)
times[i] = atof(argv[i + 1]); //input the burst time of each thread
for(i = 0; i < 5; i++)
{
status = pthread_create(&threads[i], NULL, Run, (void *)i); //Create threads
if(status != 0)
{
printf("While creating thread %d, pthread_create returned error code %d\n", i, status);
exit(-1);
}
pthread_join(threads[i], 0); //Join threads
}
}
return 0;
}
The program is directly runnable. Could anyone help me figure it out? Thanks!
Some things I've figured out reading your code:
1. At the beginning of the Run function, you convert tid (which is a pointer to void) directly to int. Shouldn't you dereference it?
It is better to make int turn volatile, so that the compiler won't make any assumptions about its value not changing.
When you call the function sleep the second time, you pass a parameter that has type double (times[i]), and you should pass an unsigned int parameter. A direct cast like (unsigned int) times[i] should solve that.
You're doing the pthread_join before creating the other threads. When you create thread 3, and it enters its busy waiting state, the other threads won't be created. Try putting the joins after the for block.
I am trying to create five threads in the main thread.
In the pthread_create() function, I am passing increasing 'num' value as a variable to function 'up' each time, so I thought the value of y in each thread should be 1,2,3,4 and 5 in a random order, respectively.
However, when printf("before add num is %d\n", y) in function 'up' is called which is to check the value of y , it shows y could be undetermined which means y may be any number between 1 to 5.
How shall I fix this parallel input problem...Thanks in advance for any help!
const int TOTAL_RUNS = 1000000;
void *up(void *ptr) {
int i;
int y = *((int*)ptr);
printf("before add num is %d\n", y);
for (i = 0; i < TOTAL_RUNS; i++)
y++;
printf("Finished adding 1 a total of %d times.\n", TOTAL_RUNS);
}
void main() {
int num = 1;
pthread_t t[5];
int i;
for (i = 0; i < 5; i++) {
pthread_create(&t[i], NULL, up,(void*) &num);
num++;
}
for (i = 0; i < 5; i++) {
pthread_join(t[i], NULL);
}
}
The problem is you're passing the same address to every thread - each thread has access to the same memory location (since you passed &num to each of them).
The cheapest way you could fix this would be to use an array:
int nums[] = {1, 2, 3, 4, 5};
/* ... */
pthread_create(&t[i], NULL, up, &nums[i]);
That should be safe since you call join in the same thread (nums won't go out of scope before the threads are done).