实现线程同步


1 为何需要线程同步?

由于线程共享进程的资源,会产生竞态条件,在某些情况下需要协调指令执行的先后顺序,也就是实现线程同步

下面是一个常见的多线程累加程序,由于sum++并不是一个原子操作,所以多个线程互相抢占从而造成计算错误。

#include
#include
#include
#include

int sum = 0;

void* add(void* arg){
    for (int i = 0; i < 10000000; ++i){
        sum++;
    }
}

int main(){
    pthread_t id;

    for (int i = 0; i < 10; ++i){
        int ret = pthread_create(&id, NULL, add, NULL);
        if(0 != ret){
            printf("Failed to create thread!\n");
            return -1;
        }
    }
    sleep(10);
    printf("%d\n", sum);
    return 0;
}

sum 的最终值应该为 100000000,但是上述代码并不会得到我们想要的结果。


2 互斥锁

解决的办法是每次只允许一个线程执行 sum++ ,在 sum++ 处加入互斥锁,上述的代码可以改写为:

#include
#include
#include
#include

int sum = 0;
pthread_mutex_t mutex;

void* add(void* arg){
    for (int i = 0; i < 10000000; ++i){
        pthread_mutex_lock(&mutex);
        sum++;
        pthread_mutex_unlock(&mutex);
    }
}

int main(){
    pthread_t id;

    pthread_mutex_init(&mutex, NULL);

    for (int i = 0; i < 10; ++i){
        int ret = pthread_create(&id, NULL, add, NULL);
        if(0 != ret){
            printf("Failed to create thread!\n");
            return -1;
        }
    }
    sleep(10);
    printf("%d\n", sum);
    return 0;
}

这样就可以稳定的得到 100000000 的结果:

3 POSIX信号量

接下来使用 POSIX 信号量来解决:

#include
#include
#include
#include
#include

int sum = 0;
sem_t sem;

void* add(void* arg){
    int tmp = 0;
    for (int i = 0; i < 10000000; ++i){
        tmp++;
    }
    sem_wait(&sem);
    sum += tmp;
    sem_post(&sem);
}

int main(){
    pthread_t id;

    sem_init(&sem, 0, 1);

    for (int i = 0; i < 10; ++i){
        int ret = pthread_create(&id, NULL, add, NULL);
        if(0 != ret){
            printf("Failed to create thread!\n");
            return -1;
        }
    }
    sleep(10);
    printf("%d\n", sum);
    return 0;
}

相关