在C中使用线程时的奇怪行为

时间:2015-03-23 10:51:04

标签: c multithreading pthreads

我对线程很新,并且很难理解下面代码的行为。假设我使用命令行输入10,我希望输出为20,因为有两个线程将count的值递增十次。但是,每次运行此程序时输出都不是20。以下是我的一些尝试:

命令行输入:10,预期输出:20,实际输出:15

命令行输入:10,预期输出:20,实际输出:10

命令行输入:10,预期输出:20,实际输出:13

命令行输入:10,例外输出:20,实际输出: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);
}

2 个答案:

答案 0 :(得分:3)

你的增量不是原子的,你没有插入任何同步机制,所以当然你的一个线程将覆盖count而另一个仍在递增它,导致增量的“损失”。

您需要一个原子增量函数(在Windows上,您有InterlockedIncrement)或显式锁定机制(如互斥锁)。

答案 1 :(得分:1)

要汇总两个数字,通常需要几个指令:

  • 将数据移入某个寄存器
  • 为该寄存器添加一些值
  • 将数据从寄存器移动到内存中的某个单元格

到目前为止,当操作系统为您的程序系统提供时间时,并不能保证所有这些操作都没有中断。这些被称为关键部分。每次进入这样的部分时,都需要同步两个线程。

这应该有效:

#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);
}