简体   繁体   中英

Strange behavior when using threads in C

I am quite new to threads and am having difficulty understanding the behavior of the code below. Suppose I use the command line input 10, I would expect the output to be 20, since there are two threads incrementing the value of count ten times each. However the output is not 20 every time I run this program. Below are some of my attempts:

Command line input: 10, Expected output: 20, Actual output: 15

Command line input: 10, Expected output: 20, Actual output: 10

Command line input: 10, Expected output: 20, Actual output: 13

Command line input: 10, Excepted output: 20, Actual output: 20

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

/* The threads will increment this count 
 * n times (command line input).
 */
int count = 0;

/* The function the threads will perform */
void *increment(void *params);


int main(int argc, char *argv[]) {

    /* Take in command line input for number of iterations */
    long iterations = (long)atoi(argv[1]);

    pthread_t thread_1, thread_2;

    /* Create two threads. */
    pthread_create(&thread_1, NULL, increment, (void*)iterations);
    pthread_create(&thread_2, NULL, increment, (void*)iterations);

    /* Wait for both to finish */
    pthread_join(thread_1, NULL);
    pthread_join(thread_2, NULL);

    /* Print the final result for count. */
    printf("Count = %d.\n", count);
    pthread_exit(NULL);

}

void *increment(void *params) {
    long iterations = (long)params;
    int i;
    /* Increment global count */
    for(i = 0; i < iterations; i++) {
        count++;
    }
    pthread_exit(NULL);
}

Your increment is not atomic and you didn't insert any synchronization mechanic, so of course your one of your threads will overwrite count while the other was still incrementing it, causing "losses" of incrementations.

You need an atomic increment function (on Windows, you have InterlockedIncrement for this), or an explicit locking mechanism (like a mutex).

To sum two numbers in assembly usually requires several instructions:

  • move data into some register
  • add some value to that register
  • move the data from the register to some cell in the memory

Thereofore, when the operating system gives your program system time, it does not guarantee that all those operations are done without any interruption. These are called critical sections. Every time you enter such a section, you'd need to syncrhonize the two threads.

This should work:

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

/* The threads will increment this count 
 * n times (command line input).
 */
int count = 0;
pthread_mutex_t lock;
/* The function the threads will perform */
void *increment(void *params);


int main(int argc, char *argv[]) {

    /* Take in command line input for number of iterations */
    long iterations = (long)atoi(argv[1]);

    pthread_t thread_1, thread_2;
    pthread_mutex_init(&lock); //initialize the mutex

    /* Create two threads. */
    pthread_create(&thread_1, NULL, increment, (void*)iterations);
    pthread_create(&thread_2, NULL, increment, (void*)iterations);

    /* Wait for both to finish */
    pthread_join(thread_1, NULL);
    pthread_join(thread_2, NULL);

    /* Print the final result for count. */
    printf("Count = %d.\n", count);
    pthread_mutex_destroy(&lock); //destroy the mutex, its similar to malloc and free
    pthread_exit(NULL);

}

void *increment(void *params) {
    long iterations = (long)params;
    int i;
    int local_count = 0;
    /* Increment global count */
    for(i = 0; i < iterations; i++) {
        local_count++;
    }

   pthread_mutex_lock(&lock); //enter a critical section
   count += local_count;
   pthread_mutex_unlock(&lock); //exit a critical section
   pthread_exit(NULL);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM