实现线程同步
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; }