Python多线程脚本转C后运行触发Segmentation Fault的解决请求
多线程Python转C后端段错误排查与解决
为提升性能,将包含多线程逻辑的Python脚本通过AI工具转换为C代码,但编译运行该C程序时遭遇Segmentation Fault(段错误)。推测问题与内存管理或线程创建相关,使用-fsanitize=address -pthread编译后得到特定错误输出。
原Python3脚本
import threading, time class creation_worker_thread: def A(starting_exec): running_list = [] for step in range(1, workers_range + 1): running_list.append(generate_thread(create_threads, (starting_exec, 0))) starting_exec += per_worker start_thread_list(running_list) def B(starting_exec): running_list = [] for step in range(1, workers_range + 1): running_list.append(generate_thread(create_threads, (starting_exec, 1))) starting_exec += per_worker start_thread_list(running_list) def C(starting_exec): running_list = [] for step in range(1, workers_range + 1): running_list.append(generate_thread(create_threads, (starting_exec, 2))) starting_exec += per_worker start_thread_list(running_list) def D(starting_exec): running_list = [] for step in range(1, workers_range + 1): running_list.append(generate_thread(create_threads, (starting_exec, 3))) starting_exec += per_worker start_thread_list(running_list) class execution_worker_thread: def A(starting_exec): running_list = [] for step in range(1, workers_range + 1): running_list.append(generate_thread(exec_threads, (starting_exec, 0))) starting_exec += per_worker start_thread_list(running_list) def B(starting_exec): running_list = [] for step in range(1, workers_range + 1): running_list.append(generate_thread(exec_threads, (starting_exec, 1))) starting_exec += per_worker start_thread_list(running_list) def C(starting_exec): running_list = [] for step in range(1, workers_range + 1): running_list.append(generate_thread(exec_threads, (starting_exec, 2))) starting_exec += per_worker start_thread_list(running_list) def D(starting_exec): running_list = [] for step in range(1, workers_range + 1): running_list.append(generate_thread(exec_threads, (starting_exec, 3))) starting_exec += per_worker start_thread_list(running_list) def main_program(value): return def generate_thread(function, argument): return threading.Thread(target=function, args=(argument,)) def start_thread_list(list): for thread in list: thread.start() for thread in list: thread.join() def exec_threads(argument): counter = 1 for thread in created_threads_list[argument[1]][argument[0]:]: thread.start() if counter >= per_worker: break counter += 1 def create_threads(argument): counter = 1 for value in request_file[argument[0]:]: created_threads_list[argument[1]].append(generate_thread(main_program, value)) if counter == per_worker: break counter += 1 def thread_workers(argument): creation_workers_list[argument[0]](argument[1]) execution_workers_list[argument[0]](0) return created_threads_list[argument[0]].clear() def exec_workers(): starting_exec, list = 0, [] for current_worker in range(max_workers): list.append(generate_thread(thread_workers, (current_worker, starting_exec))) starting_exec += per_worker * workers_range start_thread_list(list) def end_timer(start_time): run_time = "{:.2f}".format(time.time() - start_time) return print(f"Runtime: {run_time} seconds") def start_multi_threading(argument): start_time = time.time() return exec_workers(), end_timer(start_time) def share_work_load(file_length): answer = max_workers - (file_length % max_workers) if answer == max_workers: answer = 0 request_file.extend([0] * answer) file_length = len(request_file) per_worker = file_length // max_workers max_per = per_worker while per_worker >= 256: per_worker //= 2 workers_range = max_per // per_worker return workers_range, per_worker, file_length - (workers_range * per_worker * max_workers) def generate_request(testing): requests , max = [], 4096 if testing: for integer in range(1, max + 1): requests.append(integer) return requests with open('/root/lists/list.txt', 'r') as file: return file.readlines() testing = True request_file = generate_request(testing) max_workers, created_threads_list = 4, [[], [], [], []] workers_range, per_worker, remainder = share_work_load(len(request_file)) creation_workers_list = [creation_worker_thread.A, creation_worker_thread.B, creation_worker_thread.C, creation_worker_thread.D] execution_workers_list = [execution_worker_thread.A, execution_worker_thread.B, execution_worker_thread.C, execution_worker_thread.D] print(workers_range, per_worker, remainder) start_multi_threading(print('\n\033[93mrunning...\033[0m'))
转换后的C代码
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #define MAX_WORKERS 4 #define MAX_PER_WORKER 256 int per_worker; int workers_range; int remaining; // Renamed variable to avoid conflict int request_file[4096]; // Assuming a maximum size for the request file pthread_t created_threads_list[MAX_WORKERS][MAX_PER_WORKER]; void* main_program(void* arg) { // Main program logic here return NULL; } void* create_threads(void* arg) { int worker_id = *((int*)arg); int starting_exec = worker_id * workers_range * per_worker; int counter = 0; for (int i = starting_exec; i < starting_exec + per_worker; i++) { if (i >= sizeof(request_file) / sizeof(request_file[0])) { break; } pthread_create(&created_threads_list[worker_id][counter], NULL, main_program, &request_file[i]); counter++; } return NULL; } void* exec_threads(void* arg) { // Similar logic to create_threads, adjust as needed return NULL; } void start_thread_list(pthread_t* list, int size) { for (int i = 0; i < size; i++) { pthread_join(list[i], NULL); } } void exec_workers() { pthread_t thread_list[MAX_WORKERS]; for (int i = 0; i < MAX_WORKERS; i++) { pthread_create(&thread_list[i], NULL, create_threads, &i); } start_thread_list(thread_list, MAX_WORKERS); } void* thread_workers(void* arg) { int worker_id = *((int*)arg); create_threads(&worker_id); exec_threads(&worker_id); // Clearing created threads list for (int i = 0; i < MAX_PER_WORKER; i++) { pthread_cancel(created_threads_list[worker_id][i]); } return NULL; } void share_work_load(int file_length) { remaining = file_length % MAX_WORKERS; if (remaining == MAX_WORKERS) { remaining = 0; } // Adjust file length to fit evenly across workers file_length += remaining; per_worker = file_length / MAX_WORKERS; int max_per = per_worker; while (per_worker >= 256) { per_worker /= 2; } workers_range = max_per / per_worker; } void generate_request(int testing) { int max = 4096; if (testing) { for (int i = 0; i < max; i++) { request_file[i] = i + 1; } } else { FILE* file = fopen("/root/lists/list.txt", "r"); if (file == NULL) { perror("Error opening file"); exit(EXIT_FAILURE); } char line[256]; int i = 0; while (fgets(line, sizeof(line), file)) { request_file[i++] = atoi(line); } fclose(file); } } void start_quantum_threading() { generate_request(1); // Set to 1 for testing share_work_load(sizeof(request_file) / sizeof(request_file[0])); pthread_t thread_list[MAX_WORKERS]; for (int i = 0; i < MAX_WORKERS; i++) { pthread_create(&thread_list[i], NULL, thread_workers, &i); } start_thread_list(thread_list, MAX_WORKERS); } int main() { start_quantum_threading(); return 0; }
运行错误信息
zsh: segmentation fault ./compiled_script
使用-fsanitize=address -pthread编译后的输出:
AddressSanitizer: CHECK failed: sanitizer_allocator_primary64.h:131 "((kSpaceBeg)) == ((address_range.Init(TotalSpaceSize, PrimaryAllocatorName, kSpaceBeg)))" (0x600000000000, 0xfffffffffffffff4) (tid=3560) <empty stack>
问题根源分析
- 线程参数传递竞态:创建线程时直接传递栈变量
&i的地址,主线程循环修改i的值,导致子线程读取到错误的worker_id,甚至访问非法内存。 - 线程列表未初始化:全局二维数组
created_threads_list未初始化,直接调用pthread_cancel操作未创建的线程,触发未定义行为。 - 负载分配逻辑错误:原Python中会扩展
request_file使长度能被max_workers整除,但C版本仅修改file_length变量,未实际填充数组,导致后续参数计算错误。 - 核心函数未实现:
exec_threads函数为空,未按照原逻辑启动已创建的线程,导致线程资源泄漏或逻辑断裂。 - 内存越界风险:读取文件时未检查
request_file的边界,可能超出数组长度。
解决步骤
1. 修复线程参数传递竞态
为每个线程分配独立的参数内存,避免栈变量被主线程修改:
// 修改start_quantum_threading中的线程创建逻辑 void start_quantum_threading() { memset(created_threads_list, 0, sizeof(created_threads_list)); // 先初始化线程列表 generate_request(1); share_work_load(sizeof(request_file) / sizeof(request_file[0])); pthread_t thread_list[MAX_WORKERS]; for (int i = 0; i < MAX_WORKERS; i++) { int *worker_id = malloc(sizeof(int)); *worker_id = i; pthread_create(&thread_list[i], NULL, thread_workers, worker_id); } start_thread_list(thread_list, MAX_WORKERS); } // 在thread_workers中释放参数内存 void* thread_workers(void* arg) { int worker_id = *((int*)arg); free(arg); // 释放分配的内存 create_threads(&worker_id); exec_threads(&worker_id); // 修正取消线程的逻辑 for (int i = 0; i < MAX_PER_WORKER; i++) { if (created_threads_list[worker_id][i] != 0) { pthread_cancel(created_threads_list[worker_id][i]); pthread_join(created_threads_list[worker_id][i], NULL); // 等待线程结束 created_threads_list[worker_id][i] = 0; } } return NULL; }
2. 修正负载分配函数逻辑
模拟原Python的数组扩展行为,确保文件长度能被MAX_WORKERS整除:
void share_work_load(int file_length) { int remainder = file_length % MAX_WORKERS; if (remainder != 0) { int add_count = MAX_WORKERS - remainder; // 填充0扩展数组,避免越界 for (int i = file_length; i < file_length + add_count && i < 4096; i++) { request_file[i] = 0; } file_length += add_count; } per_worker = file_length / MAX_WORKERS; int max_per = per_worker; while (per_worker >= 256) { per_worker /= 2; } workers_range = max_per / per_worker; }
3. 实现exec_threads核心逻辑
按照原Python逻辑启动并等待已创建的线程:
void* exec_threads(void* arg) { int worker_id = *((int*)arg); int counter = 0; for (int i = 0; i < per_worker; i++) { if (created_threads_list[worker_id][i] != 0) { pthread_join(created_threads_list[worker_id][i], NULL); // 等待线程执行完成 counter++; if (counter >= per_worker) break; } } return NULL; }
4. 添加内存边界检查
在读取文件时避免数组越界:
void generate_request(int testing) { int max = 4096; if (testing) { for (int i = 0; i < max; i++) { request_file[i] = i + 1; } } else { FILE* file = fopen("/root/lists/list.txt", "r"); if (file == NULL) { perror("Error opening file"); exit(EXIT_FAILURE); } char line[256]; int i = 0; while (fgets(line, sizeof(line), file) && i < 4096) { // 添加边界检查 request_file[i++] = atoi(line); } fclose(file); } }
编译与运行
使用以下命令编译代码,启用线程支持和地址 sanitizer:
gcc -o compiled_script your_code.c -pthread -fsanitize=address
运行编译后的程序即可解决段错误问题。
内容的提问来源于stack exchange,提问作者Æmmy
相关产品推荐
相关产品推荐

