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

Windows10环境下Visual Studio 2019运行pthread并行代码出现0xC0000005访问违例错误的修复求助

分析与修复你的pthread并行代码崩溃问题

首先,你的错误0xC0000005: Access violation reading location 0x00000000是典型的非法内存访问,结合你的代码,主要是线程取消导致的无效指针解引用和数据竞争这两个核心问题,下面逐一拆解并修复:

核心问题定位

1. 全局partial_sum的无保护竞争

所有消费者线程共用同一个全局partial_sum,且修改时没有加锁。多个线程同时读写同一个变量会触发数据竞争,这属于C++未定义行为,可能导致数值错乱,甚至直接触发内存访问错误。

2. 线程取消引发的无效指针解引用

你的consumer_interruptor_routine一直在尝试取消消费者线程,虽然消费者线程开头设置了PTHREAD_CANCEL_DISABLE,但std::this_thread::sleep_for是线程取消点——当线程处于取消禁用状态时,取消请求会被挂起,一旦后续代码启用取消(哪怕你没写,也可能因某些操作间接触发),线程会异常终止,返回PTHREAD_CANCELED(通常是(void*)-1或空指针)。此时在run_threads中解引用*return_value就会触发访问违例。

3. 条件变量的锁与检查不匹配

生产者等待消费者处理完成时,用producer_mutex保护对*shared_variable_pointer的检查,但该变量实际由shared_variable_mutex管控,这导致条件检查不在正确的锁范围内,可能出现逻辑混乱,比如生产者误以为数据未被处理而无限等待。

4. is_running的内存可见性问题

is_running是全局变量,消费者线程读取它时没有加锁或使用原子操作,可能因CPU缓存优化导致线程无法及时感知is_running的变化,出现死循环或提前退出的情况。

修复方案与代码修改

下面是修复后的完整代码,我会标注关键修改点:

using namespace std;
#include <pthread.h>
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <random>
#include <thread>
#include <atomic>
#pragma warning( disable : 4091 )

struct thread_primitives {
    pthread_mutex_t shared_variable_mutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_mutex_t producer_mutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t value_produced_condition = PTHREAD_COND_INITIALIZER;
    pthread_cond_t value_consumed_condition = PTHREAD_COND_INITIALIZER;
    pthread_mutex_t sum_mutex = PTHREAD_MUTEX_INITIALIZER; // 新增:保护sum的锁
};

// 用原子变量确保is_running的内存可见性
std::atomic<bool> is_running = true;
unsigned int number_of_consumers;
int consumer_sleep_upper_limit = 0;
pthread_barrier_t consumers_barrier;
std::vector<pthread_t> consumers;
thread_primitives primitives;
int total_sum = 0; // 改用全局total_sum,避免每个线程返回局部指针问题

int get_random_integer(int lower_limit, int upper_limit) {
    static std::random_device dev;
    static std::mt19937 generator(dev()); // 改为静态,避免重复初始化随机数生成器
    std::uniform_int_distribution<int> distribution(lower_limit, upper_limit);
    return distribution(generator);
}

void* producer_routine(void* arg) {
    pthread_barrier_wait(&consumers_barrier);
    int* shared_variable_pointer = static_cast<int*>(arg);
    std::string input;
    std::getline(std::cin, input);
    std::stringstream ss(input);
    int n;
    while (ss >> n) {
        pthread_mutex_lock(&primitives.shared_variable_mutex);
        *shared_variable_pointer = n;
        pthread_cond_signal(&primitives.value_produced_condition);
        pthread_mutex_unlock(&primitives.shared_variable_mutex);

        // 修改:用shared_variable_mutex保护对shared_variable的检查
        pthread_mutex_lock(&primitives.shared_variable_mutex);
        while (*shared_variable_pointer != 0) {
            // 等待消费者处理完成,条件变量关联正确的锁
            pthread_cond_wait(&primitives.value_consumed_condition, &primitives.shared_variable_mutex);
        }
        pthread_mutex_unlock(&primitives.shared_variable_mutex);
    }

    pthread_mutex_lock(&primitives.shared_variable_mutex);
    is_running = false;
    pthread_cond_broadcast(&primitives.value_produced_condition);
    pthread_mutex_unlock(&primitives.shared_variable_mutex);

    return nullptr;
}

void* consumer_routine(void* arg) {
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);
    pthread_barrier_wait(&consumers_barrier);
    int* shared_variable_pointer = static_cast<int*>(arg);

    while (is_running) {
        pthread_mutex_lock(&primitives.shared_variable_mutex);
        while (is_running && *shared_variable_pointer == 0) {
            pthread_cond_wait(&primitives.value_produced_condition, &primitives.shared_variable_mutex);
        }
        if (!is_running) { // 检查是否要退出,避免处理无效数据
            pthread_mutex_unlock(&primitives.shared_variable_mutex);
            break;
        }
        int current_value = *shared_variable_pointer;
        *shared_variable_pointer = 0;

        pthread_cond_signal(&primitives.value_consumed_condition);
        pthread_mutex_unlock(&primitives.shared_variable_mutex);

        // 用sum_mutex保护total_sum的修改
        pthread_mutex_lock(&primitives.sum_mutex);
        total_sum += current_value;
        pthread_mutex_unlock(&primitives.sum_mutex);

        std::this_thread::sleep_for(std::chrono::milliseconds(get_random_integer(0, consumer_sleep_upper_limit)));
    }
    return nullptr; // 不再返回指针,直接修改全局total_sum
}

void* consumer_interruptor_routine(void* arg) {
    pthread_barrier_wait(&consumers_barrier);
    // 修改:只有当is_running为true时才尝试取消,且取消前先启用消费者的取消状态
    while (is_running) {
        int idx = get_random_integer(0, number_of_consumers - 1);
        // 临时启用消费者线程的取消状态
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, nullptr);
        pthread_cancel(consumers[idx]);
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);
        // 取消后短暂休眠,避免频繁取消
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    return nullptr;
}

int run_threads() {
    pthread_barrier_init(&consumers_barrier, nullptr, number_of_consumers + 2);
    int updates_variable = 0;
    pthread_t producer, interrupter;
    pthread_create(&producer, nullptr, producer_routine, &updates_variable);

    consumers = std::vector<pthread_t>(number_of_consumers);
    for (auto& consumer : consumers) {
        pthread_create(&consumer, nullptr, consumer_routine, &updates_variable);
    }

    pthread_create(&interrupter, nullptr, consumer_interruptor_routine, nullptr);

    pthread_join(producer, nullptr);
    pthread_join(interrupter, nullptr);

    // 等待所有消费者线程结束
    for (auto& consumer : consumers) {
        pthread_join(consumer, nullptr);
    }

    // 销毁同步原语,避免资源泄漏
    pthread_barrier_destroy(&consumers_barrier);
    pthread_mutex_destroy(&primitives.shared_variable_mutex);
    pthread_mutex_destroy(&primitives.producer_mutex);
    pthread_mutex_destroy(&primitives.sum_mutex);
    pthread_cond_destroy(&primitives.value_produced_condition);
    pthread_cond_destroy(&primitives.value_consumed_condition);

    return total_sum;
}

int main(int argc, char* argv[]) {
    if (argc != 3) { // 新增参数检查,避免非法输入
        std::cerr << "Usage: " << argv[0] << " <number_of_consumers> <consumer_sleep_upper_limit>" << std::endl;
        return 1;
    }
    try {
        number_of_consumers = static_cast<unsigned int>(std::stoi(argv[1]));
        consumer_sleep_upper_limit = std::stoi(argv[2]);
    } catch (...) {
        std::cerr << "Invalid arguments, please enter integers." << std::endl;
        return 1;
    }
    std::cout << run_threads() << std::endl;
    return 0;
}

关键修改说明:

  • 原子变量is_running:用std::atomic<bool>替代普通bool,确保线程间的内存可见性,避免CPU缓存导致的感知延迟。
  • 新增sum_mutex:保护全局total_sum的修改,彻底消除数据竞争。
  • 条件变量锁匹配:生产者等待消费者处理时,改用shared_variable_mutex保护对共享变量的检查,确保条件判断的原子性。
  • 取消逻辑修正:中断者线程在取消消费者前临时启用其取消状态,同时添加短暂休眠避免频繁取消,降低线程异常终止的概率;消费者线程退出前检查is_running,避免处理无效数据。
  • 随机数生成器优化:将随机数生成器改为静态,避免每次调用get_random_integer都重新初始化,提升性能和随机性。
  • 资源清理:添加同步原语的销毁代码,避免资源泄漏;新增参数检查,防止非法输入导致的崩溃。
  • 避免指针返回问题:不再让消费者返回局部/全局指针,直接修改全局total_sum,彻底解决线程取消后无效指针解引用的问题。

测试说明

运行时请确保输入合法的整数参数,比如:

./parallel_computiong_hw2.exe 3 100

然后输入一串整数(比如1 2 3 4 5),程序会输出它们的总和。

内容的提问来源于stack exchange,提问作者Shah

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 17:47:30