多线程数组迭代:不使用mutex的计数问题通用解决方案
最常用的无Mutex解决方案:彻底规避共享变量竞争
这个问题太典型了——很多人刚写多线程代码时都会踩共享变量争抢的坑,不想用mutex的话,最常用也最高效的方案是从根源上消除竞争:给每个线程分配独立的私有计数变量,完全避开临界区问题。
为什么共享变量i会导致计数失败?
你遇到的核心问题是多个线程同时读写同一个共享变量i:线程A刚把i加到3,线程B可能立刻把它重置为0,最终所有线程的计数逻辑全乱套。mutex是通过加锁串行化访问来解决,但既然不想用锁,最优解就是不让线程共享这个计数变量。
方案1:线程私有局部变量(首选)
这是最简单直接的写法,每个线程用自己的局部变量计数,完全没有竞争:
Python 示例
import threading def thread_counter(): # 每个线程的num都是独立的局部变量,和其他线程无关 for num in range(10): print(f"Thread ID {threading.get_ident()}: 计数到 {num}") # 启动5个线程,每个都独立完成0-9的计数 for _ in range(5): t = threading.Thread(target=thread_counter) t.start()
C 语言示例
#include <pthread.h> #include <stdio.h> void *thread_counter(void *arg) { // 局部变量num,每个线程拥有独立副本 for (int num = 0; num < 10; num++) { printf("Thread %ld: 计数到 %d\n", pthread_self(), num); } return NULL; } int main() { pthread_t threads[5]; for (int i = 0; i < 5; i++) { pthread_create(&threads[i], NULL, thread_counter, NULL); } for (int i = 0; i < 5; i++) { pthread_join(threads[i], NULL); } return 0; }
方案2:传递独立参数(针对需要主线程分配初始值的场景)
如果你的场景是主线程需要给每个线程分配不同的起始值,但之前因传递共享i的地址导致覆盖,可以给每个线程单独分配参数内存:
C 语言示例
#include <pthread.h> #include <stdio.h> #include <stdlib.h> void *thread_counter(void *arg) { int start_val = *(int*)arg; free(arg); // 记得释放分配的内存 for (int num = start_val; num < start_val + 10; num++) { printf("Thread %ld: 计数到 %d\n", pthread_self(), num); } return NULL; } int main() { pthread_t threads[5]; for (int i = 0; i < 5; i++) { int *start_ptr = malloc(sizeof(int)); *start_ptr = i * 10; // 每个线程从不同起始值开始数10个数 pthread_create(&threads[i], NULL, thread_counter, start_ptr); } for (int i = 0; i < 5; i++) { pthread_join(threads[i], NULL); } return 0; }
方案3:线程本地存储(TLS,适合跨函数共享线程私有数据)
如果你的计数变量需要在多个函数间共享,但又不想让线程互相干扰,可以用线程本地存储——每个线程会拥有该变量的独立副本:
C 语言示例(__thread关键字)
#include <pthread.h> #include <stdio.h> __thread int num; // 线程本地存储,每个线程有自己的num副本 void increment_num() { num++; // 仅修改当前线程的num } void *thread_counter(void *arg) { num = 0; for (int i = 0; i < 10; i++) { printf("Thread %ld: 计数到 %d\n", pthread_self(), num); increment_num(); } return NULL; } int main() { pthread_t threads[5]; for (int i = 0; i < 5; i++) { pthread_create(&threads[i], NULL, thread_counter, NULL); } for (int i = 0; i < 5; i++) { pthread_join(threads[i], NULL); } return 0; }
Python 示例(threading.local())
import threading thread_local = threading.local() def increment_num(): thread_local.num += 1 def thread_counter(): thread_local.num = 0 for _ in range(10): print(f"Thread ID {threading.get_ident()}: 计数到 {thread_local.num}") increment_num() for _ in range(5): t = threading.Thread(target=thread_counter) t.start()
为什么这些方案比Mutex好?
Mutex需要线程等待锁,会带来上下文切换的开销,写不好还容易死锁。而用私有变量或TLS,完全没有竞争,线程可以独立执行,效率更高,代码也更简洁。
内容的提问来源于stack exchange,提问作者Art Em
相关产品推荐
相关产品推荐

