Symmetrical multiprocessor output

Consider this code:

int x; //declared globally

for( int i=0; i<1000000; i++)
           x++;

printf("%d",x);

      

This is the main logic of the program, ignore the syntax for creating streams, etc.

Now I have created two threads and the program runs a race condition when it runs (obviously!).

For simplicity, let's assume that the entire for loop starts in one pass for a thread, before the second thread is executed (assuming a uniprocessor system). So the ideal expected result is 1 million for thread 1 and 2 million for question 2. (Though which thread prints 2 million depending on the CPU scheduler)

My first question: As per the definition of a race condition, could the fact that 1st exit and 2nd exit are mixed every time I run the program count as a race condition? Why?

Second question: Consider a multiprocessing system that runs a for loop 1 million times in both threads at the same time. What is the ideal result? Why?

+3


source to share


1 answer


I will provide some sample code to demonstrate the scenario described, except that I will eliminate the difference due to the time between the end of the loop and the printout. I will use a temporary local variable for this.

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

pthread_mutex_t x_mutex = PTHREAD_MUTEX_INITIALIZER;
int x = 0;

void *
task_function(void *ptr)
{
    int index;
    int last = 0;

    for (index = 0; index < 1000000; index++) {
        pthread_mutex_lock(&x_mutex);
        last = ++x;
        pthread_mutex_unlock(&x_mutex);
    }

    /* Use last since it won't matter how much time elapses
     * after the loop ends and when the printf is done */
    printf("x = %d\n", last);

}

int
main()
{
    pthread_t thread1, thread2;
    int retval1, retval2;

    /* Create two independent threads which will each execute task_function */
    retval1 = pthread_create(&thread1, NULL, task_function, NULL);
    retval2 = pthread_create(&thread2, NULL, task_function, NULL);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
}

      

If you run this code, the final thread should always print 2,000,000 to complete. If it doesn't, there is a serious error. However, the first one, to be completed, will print a value that really won't be deterministic unless you know exactly how the scheduler divided tasks and how fast each thread ran.



To drive home. Let's say that the loop was 5

instead of 1,000,000. And let's say the threads were running concurrently at the same speed and each step was interlaced. So stream 0 increments the first step and increments x

to 1. Increments stream 2 and now 2

. after all, if this pattern repeats, then Thread 1 will be the first to loop 5 times and it will see the value 9

. Then thread 2 will terminate it and display the value 10

. As you can see, depending on how things are planned, both theories could theoretically approximate if the work is divided equally. Therefore, in this example, instead of printing 5

and 10

it is printed 9

and 10

.

Without proper mutexes / critical sections / atomic operations associated with x

, the code might not even display 2,000,000. This is because updates x

from both threads can compress against each other, producing values x

that are not correct. If you've pulled the mutexes in task_function

, you'll probably find the results to be pretty fluffy.

+1


source







All Articles