You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C语言循环链表按条件删除节点时多节点场景崩溃问题求助

我帮你排查下这段循环链表删除代码的问题,以及给出修复方案——你遇到的多节点删除崩溃,主要是指针逻辑混乱和线程安全问题导致的:

原代码的核心问题

  • prev指针完全没更新:你把prev初始化为head后,就再也没动过它。当删除中间节点时,prev可能指向已经被释放的内存,或者根本不是当前节点的前一个节点,调用prev->next直接触发非法内存访问。
  • 野指针触发崩溃:first初始化为原head,但如果head节点被删除,first就成了野指针,后续first != temp的判断会访问无效内存,直接崩。
  • 循环遍历逻辑漏洞:do-while的终止条件不合理,删除节点后temp的指向混乱,要么提前终止遍历,要么进入无限循环,最终导致崩溃。
  • 线程安全隐患:多个线程同时操作链表却没加锁,会出现竞态条件(比如一个线程在删节点,另一个在加节点),直接破坏链表结构,崩溃是必然的。

修复后的完整代码

#include <pthread.h>

// 全局互斥锁:所有操作这个链表的函数(入队、删除、遍历)都必须用它同步
pthread_mutex_t list_mutex = PTHREAD_MUTEX_INITIALIZER;

struct data* delete_nodes(struct data *head) {
    pthread_mutex_lock(&list_mutex); // 先加锁,保证线程安全

    // 空链表直接返回,不用走后续逻辑
    if (head == NULL) {
        pthread_mutex_unlock(&list_mutex);
        return NULL;
    }

    struct data *current = head;
    struct data *prev = NULL;
    struct data *new_head = head; // 跟踪最新的头节点,避免原head被释放后丢失链表

    do {
        if (current->status == true) {
            struct data *to_delete = current;

            // 处理头节点删除的特殊情况
            if (current == new_head) {
                if (current->next == new_head) {
                    // 只剩最后一个节点,删除后链表为空
                    new_head = NULL;
                    current = NULL;
                } else {
                    // 找到尾节点,让尾节点指向新的头(current的下一个节点)
                    struct data *tail = new_head;
                    while (tail->next != new_head) {
                        tail = tail->next;
                    }
                    new_head = current->next;
                    tail->next = new_head;
                    current = new_head;
                }
            } else {
                // 中间或尾部节点删除,直接让前一个节点指向当前节点的下一个
                prev->next = current->next;
                current = prev->next;
            }

            free(to_delete); // 释放被删除的节点
        } else {
            // 当前节点不用删,移动指针:prev跟着current走,current到下一个节点
            prev = current;
            current = current->next;
        }

        // 循环终止条件:链表为空,或者已经遍历完一圈回到新的头节点
    } while (new_head != NULL && current != new_head);

    pthread_mutex_unlock(&list_mutex); // 解锁
    return new_head;
}

关键修复点说明

  1. 强制线程安全:加了互斥锁,所有操作这个链表的地方(比如你的入队函数)必须同样加锁,否则多线程环境下还是会出问题。
  2. 正确管理指针:只有当节点不删除时才更新prev,删除节点时根据是否是头节点做不同处理,彻底避免指针越界或访问已释放内存。
  3. 头节点删除的闭环处理:循环链表删头节点时,必须找到尾节点并让它指向新的头,保证链表的循环结构不被破坏。
  4. 避免野指针:用new_head跟踪最新的头,遍历终止条件改成current != new_head,确保只遍历一圈,不会访问已释放的原head指针。
  5. 清晰的边界处理:单独处理空链表和单节点删除的情况,逻辑更稳定。

额外注意事项

  • 你的入队函数也必须加同一把list_mutex锁,不然多线程同时入队和删除还是会崩。
  • 确保所有节点都是用malloc分配的,删除时用free,避免内存泄漏或双重释放。
  • 如果status变量会被多个线程修改,最好用volatile修饰它,保证内存可见性。

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

火山引擎 最新活动