Linux c实现一个线程安全的单链表

slist.h

#ifndef SLIST_H
#define SLIST_H

#include <pthread.h>
#include <stdbool.h>

// 单链表节点结构
typedef struct SListNode
{
    void *pdata;            // 存储数据的指针
    struct SListNode *next; // 指向下一个节点的指针
} SListNode;

// 单链表结构
typedef struct SList
{
    SListNode *head;      // 链表的头指针
    pthread_mutex_t lock; // 互斥锁
} SList;

// 比较函数指针类型,返回值为0表示相等
typedef int (*CompareCallback)(void *pdata1, void *pdata2);

// 释放函数指针类型
typedef void (*FreeCallback)(void *pdata);

// 遍历函数指针类型
typedef void (*TraverseCallback)(const void *pdata, void *arg);

/**
 * 初始化链表。
 *
 * @param list 需要初始化的链表指针。
 * @return 初始化是否成功(0 表示成功,-1 表示失败)。
 */
int slist_init(SList *list);

/**
 * 销毁链表,释放所有资源。
 *
 * @param list 需要销毁的链表指针。
 * @param free_cb 自定义的释放函数,如果为 NULL,使用 free。
 */
void slist_destroy(SList *list, FreeCallback free_cb);

/**
 * 添加数据
 *
 * @param list 链表指针。
 * @param pdata 要添加的数据指针。
 * @param size 数据的大小。
 * @return 操作是否成功(0 表示成功,-1 表示失败)。
 */
int slist_insert(SList *list, void *pdata, size_t size);

/**
 * 删除数据
 *
 * @param list 链表指针。
 * @param pdata 要删除的节点数据指针。
 * @param compare_cb 自定义的比较函数。
 * @param free_cb 自定义的释放函数,如果为 NULL,使用 free。
 * @return 操作是否成功(0 表示成功,-1 表示失败)。
 */
int slist_remove(SList *list, void *pdata, CompareCallback compare_cb, FreeCallback free_cb);

/**
 * 查找数据
 *
 * @param list 链表指针。
 * @param pdata 要查找的数据指针。
 * @param compare_cb 自定义的比较函数。
 * @return 如果找到,返回对应的节点数据;否则返回 NULL。
 */
const void *slist_find(SList *list, void *pdata, CompareCallback compare_cb);

/**
 * 修改数据
 *
 * @param list 链表指针。
 * @param old_data 需要修改的节点数据指针。
 * @param new_data 替换为的新数据指针。
 * @param size 数据的大小。
 * @param compare_cb 自定义的比较函数。
 * @return 操作是否成功(0 表示成功,-1 表示失败)。
 */
int slist_modify(SList *list, void *old_data, void *new_data, size_t size,
                 CompareCallback compare_cb);

/**
 * 遍历链表
 *
 * @param list 链表指针。
 * @param traverse_cb 自定义的遍历函数。
 * @param arg 回调携带的参数。
 * @return 操作是否成功(0 表示成功,-1 表示失败)。
 */
int slist_foreach(SList *list, TraverseCallback traverse_cb, void *arg);

/**
 * 遍历链表
 *
 * @param list 链表指针。
 * @param pdata 遍历到的节点数据指针,函数内部会分配内存,需要调用者释放。
 * @param count 遍历到的节点数量。
 * @return 操作是否成功(0 表示成功,-1 表示失败)。
 */
int slist_foreach2(SList *list, void ***pdata, size_t *count);

/**
 * 释放遍历链表时分配的内存。
 *
 * @param pdata 遍历到的节点数据指针。
 * @return 无。
 */
void slist_free_foreach2(void ***pdata);

/**
 * 获取链表中元素数量
 *
 * @param list 链表指针。
 * @return 链表中元素的数量。
 */
size_t slist_size(SList *list);

/**
 * 链表是否为空。
 *
 * @param list 链表指针。
 * @return 如果链表为空,返回 true;否则返回 false。
 */
bool slist_empty(SList *list);

/**
 * 清空链表,释放所有节点。
 *
 * @param list 链表指针。
 * @param free_cb 自定义的释放函数,如果为 NULL,使用 free。
 * @return 无。
 */
void slist_clear(SList *list, FreeCallback free_cb);

#endif // SLIST_H

slist.c

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "slist.h"

int slist_init(SList *list)
{
    list->head = NULL;
    if (pthread_mutex_init(&list->lock, NULL) != 0)
    {
        return -1; // 初始化互斥锁失败
    }
    return 0;
}

void slist_destroy(SList *list, FreeCallback free_cb)
{
    pthread_mutex_lock(&list->lock);

    SListNode *current = list->head;
    while (current)
    {
        SListNode *next = current->next;
        // 释放节点数据,如果没提供自定义释放函数,使用free
        (free_cb) ? free_cb(current->pdata) : free(current->pdata);
        free(current);
        current = next;
    }
    list->head = NULL;

    pthread_mutex_unlock(&list->lock);
    pthread_mutex_destroy(&list->lock);
}

int slist_insert(SList *list, void *pdata, size_t size)
{
    SListNode *new_node = (SListNode *)malloc(sizeof(SListNode));
    uint8_t *data = (uint8_t *)malloc(size);
    if (!new_node || !data)
    {
        free(new_node);
        free(data);
        return -1; // 分配内存失败
    }
    memcpy(data, pdata, size);
    new_node->pdata = data;
    pthread_mutex_lock(&list->lock);

    // 头插法
    new_node->next = list->head;
    list->head = new_node;

    pthread_mutex_unlock(&list->lock);
    return 0;
}

int slist_remove(SList *list, void *pdata, CompareCallback compare_cb, FreeCallback free_cb)
{
    if (!compare_cb)
    {
        return -1;
    }
    pthread_mutex_lock(&list->lock);

    SListNode *current = list->head;
    SListNode *previous = NULL;

    while (current)
    {
        if (compare_cb(current->pdata, pdata) == 0)
        {
            if (previous)
            {
                previous->next = current->next;
            }
            else
            {
                list->head = current->next;
            }
            (free_cb) ? free_cb(current->pdata) : free(current->pdata);
            free(current);
            pthread_mutex_unlock(&list->lock);
            return 0;
        }
        previous = current;
        current = current->next;
    }

    pthread_mutex_unlock(&list->lock);
    return -1; // 未找到数据
}

const void *slist_find(SList *list, void *pdata, CompareCallback compare_cb)
{
    if (!compare_cb)
    {
        return NULL;
    }
    pthread_mutex_lock(&list->lock);

    SListNode *current = list->head;
    while (current)
    {
        if (compare_cb(current->pdata, pdata) == 0)
        {
            pthread_mutex_unlock(&list->lock);
            return current->pdata;
        }
        current = current->next;
    }

    pthread_mutex_unlock(&list->lock);
    return NULL; // 未找到数据
}

int slist_modify(SList *list, void *old_data, void *new_data, size_t size,
                 CompareCallback compare_cb)
{
    if (!compare_cb)
    {
        return -1;
    }
    pthread_mutex_lock(&list->lock);

    SListNode *current = list->head;
    while (current)
    {
        if (compare_cb(current->pdata, old_data) == 0)
        {
            memcpy(current->pdata, new_data, size);
            pthread_mutex_unlock(&list->lock);
            return 0;
        }
        current = current->next;
    }

    pthread_mutex_unlock(&list->lock);
    return -1; // 未找到数据
}

int slist_foreach(SList *list, TraverseCallback traverse_cb, void *arg)
{
    if (!traverse_cb)
    {
        return -1;
    }
    pthread_mutex_lock(&list->lock);

    SListNode *current = list->head;
    while (current)
    {
        traverse_cb(current->pdata, arg);
        current = current->next;
    }

    pthread_mutex_unlock(&list->lock);
    return 0;
}

int slist_foreach2(SList *list, void ***pdata, size_t *count)
{
    pthread_mutex_lock(&list->lock);

    size_t size = 0;
    SListNode *current = list->head;

    while (current)
    {
        size++;
        current = current->next;
    }
    *pdata = (void *)malloc(sizeof(void *) * size);
    if (!*pdata)
    {
        pthread_mutex_unlock(&list->lock);
        return -1; // 分配内存失败
    }

    current = list->head;
    for (size_t i = 0; i < size; i++)
    {
        (*pdata)[i] = current->pdata;
        current = current->next;
    }
    *count = size;

    pthread_mutex_unlock(&list->lock);
    return 0;
}

void slist_free_foreach2(void ***pdata)
{
    free(*pdata);
    *pdata = NULL;
}

size_t slist_size(SList *list)
{
    size_t size = 0;
    pthread_mutex_lock(&list->lock);

    SListNode *current = list->head;
    while (current)
    {
        size++;
        current = current->next;
    }

    pthread_mutex_unlock(&list->lock);
    return size;
}

bool slist_empty(SList *list)
{
    pthread_mutex_lock(&list->lock);

    bool is_empty = (list->head == NULL);

    pthread_mutex_unlock(&list->lock);
    return is_empty;
}

void slist_clear(SList *list, FreeCallback free_cb)
{
    pthread_mutex_lock(&list->lock);

    SListNode *next = NULL;
    SListNode *current = list->head;
    while (current)
    {
        next = current->next;
        (free_cb) ? free_cb(current->pdata) : free(current->pdata);
        free(current);
        current = next;
    }
    list->head = NULL;

    pthread_mutex_unlock(&list->lock);
}

测试:

#include <stdio.h>
#include <stdlib.h>
#include "slist.h"

int CompareFun(void *pdata1, void *pdata2)
{
    return *(int *)pdata1 - *(int *)pdata2;
}

void TraverseFun(const void *pdata, void *)
{
    printf("%d\n", *(int *)pdata);
}

int main(void)
{
    SList list;
    int buf[10] = {0};

    for (int i = 0; i < 10; i++)
    {
        buf[i] = i;
    }

    slist_init(&list);
    for (int i = 0; i < 10; i++)
        slist_insert(&list, &buf[i], sizeof(int));

    printf("size = %zu\n", slist_size(&list));
    if (slist_empty(&list))
        printf("empty\n");
    else
        printf("not empty\n");

    // 遍历
    printf("--------\n");
    slist_foreach(&list, TraverseFun, NULL);
    printf("--------\n");

    size_t count = 0;
    void **pdata2 = NULL;
    slist_foreach2(&list, &pdata2, &count);
    printf("\ncount = %zu\n", count);
    printf("--------\n");
    for (size_t i = 0; i < count; i++)
    {
        printf("%d\n", *((int *)pdata2[i]));
    }
    printf("--------\n");
    slist_free_foreach2(&pdata2);

    const int *p = slist_find(&list, &buf[3], CompareFun);
    if (p)
        printf("found: %d\n", *p);
    else
        printf("Not found\n");

    printf("remove\n");
    slist_remove(&list, &buf[3], CompareFun, NULL);
    p = slist_find(&list, &buf[3], CompareFun);
    if (p)
        printf("found: %d\n", *p);
    else
        printf("Not found\n");

    int *pValue = (int *)malloc(sizeof(int));
    *pValue = 666;
    slist_modify(&list, &buf[0], pValue, sizeof(int), CompareFun);
    p = slist_find(&list, pValue, CompareFun);
    if (p)
        printf("found: %d\n", *p);
    else
        printf("Not found\n");

    printf("clear\n");
    slist_clear(&list, NULL);
    printf("size = %zu\n", slist_size(&list));
    if (slist_empty(&list))
        printf("empty\n");
    else
        printf("not empty\n");

    slist_destroy(&list, NULL);

    return 0;
}

测试输出:

size = 10
not empty
--------
9
8
7
6
5
4
3
2
1
0
--------

count = 10
--------
9
8
7
6
5
4
3
2
1
0
--------
found: 3
remove
Not found
found: 666
clear
size = 0
empty

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值