You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程数组迭代:不使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:30:27