C语言 对整数的自增操作原子性问题

C语言中,对整数的自增操作(++)并不是原子操作,也就是在多线程或多核环境中,当多个线程同时对同一个整数进行自增时,可能会发生竞争条件(race condition),导致结果不正确。在多线程环境下,对同一个整数变量进行自增操作时,可能会出现竞态条件,导致最终结果的不确定性。

1、C语言中的原子性

原子操作是指该操作作为一个单一的、不被中断的步骤执行。在多线程环境中,原子操作保证操作完成时不被其他线程干扰,从而避免了竞争条件。C 语言中,i++ 操作默认不是原子操作。在单线程环境中,由于没有其他线程修改变量,因此没有原子性的问题。在多线程程序中,当多个线程同时对 i 进行自增操作时,除非使用同步机制(如互斥锁或 C11 中提供的原子操作),否则可能会出现竞争条件。

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

atomic_int shared_counter = 0;  // 原子类型,确保线程安全

void* increment(void* arg) {
    for (int i = 0; i < 100000; i++) {
        atomic_fetch_add(&shared_counter, 1);  // 原子增加
    }
    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    // 创建两个线程
    pthread_create(&thread1, NULL, increment, NULL);
    pthread_create(&thread2, NULL, increment, NULL);

    // 等待线程完成
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    printf("Final counter value: %d\n", shared_counter);

    return 0;
}

2、C11 中的 stdatomic.h

为了执行原子操作,可以使用 C11 的 库,它提供了原子类型和操作,确保线程安全。

#include <stdio.h>
#include <stdatomic.h>

int main() {
    atomic_int i = 0;

    // 原子自增
    atomic_fetch_add(&i, 1);

    printf("i: %d\n", i);
    return 0;
}

没有原子操作时,在多线程程序中自增操作可能会遇到竞争条件:

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

int i = 0;

void *increment(void *arg) {
    for (int j = 0; j < 100000; j++) {
        i++;  // 不是原子操作,可能会导致竞争条件
    }
    return NULL;
}

int main() {
    pthread_t t1, t2;
    
    pthread_create(&t1, NULL, increment, NULL);
    pthread_create(&t2, NULL, increment, NULL);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    printf("Final value of i: %d\n", i);
    return 0;
}

3、使用互斥锁的解决方案

为了避免竞争条件,可以使用互斥锁来同步对变量的访问,pthread_mutex_lockpthread_mutex_unlock 保证每次只有一个线程可以访问i,从而避免了竞争条件。

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

int i = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void *increment(void *arg) {
    for (int j = 0; j < 100000; j++) {
        pthread_mutex_lock(&lock);
        i++;
        pthread_mutex_unlock(&lock);
    }
    return NULL;
}

int main() {
    pthread_t t1, t2;
    
    pthread_create(&t1, NULL, increment, NULL);
    pthread_create(&t2, NULL, increment, NULL);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    printf("Final value of i: %d\n", i);
    return 0;
}

推荐阅读
cjavapy编程之路首页