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

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>

问题根源分析

  1. 线程参数传递竞态:创建线程时直接传递栈变量&i的地址,主线程循环修改i的值,导致子线程读取到错误的worker_id,甚至访问非法内存。
  2. 线程列表未初始化:全局二维数组created_threads_list未初始化,直接调用pthread_cancel操作未创建的线程,触发未定义行为。
  3. 负载分配逻辑错误:原Python中会扩展request_file使长度能被max_workers整除,但C版本仅修改file_length变量,未实际填充数组,导致后续参数计算错误。
  4. 核心函数未实现:exec_threads函数为空,未按照原逻辑启动已创建的线程,导致线程资源泄漏或逻辑断裂。
  5. 内存越界风险:读取文件时未检查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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 12:10:54