Windows10环境下Visual Studio 2019运行pthread并行代码出现0xC0000005访问违例错误的修复求助
首先,你的错误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

