数据结构零基础入门(初学者也能看懂):队列使用场景之无锁技术

介绍一种思路,可以减少锁操作,不是绝对的无锁,但可以大大降低锁的数量。真正的无锁技术后续专门更文。

为什么要使用无锁技术?

为了高效,锁的开销很大,会导致性能下降。(后续更文介绍为什么锁的开销大)

锁的逻辑和使用:多个线程读写共同资源(称作:竞争资源),为保持同步(即,防止一起操作造成混乱),独占资源并使用。A拿到该资源即上锁,B线程再来操作该资源,因拿不到锁而被迫等待。A用完资源释放锁,此时其他线程才有机会操作该资源。

这样,造成的问题就是低效,线程拿到时间片却拿不到资源,于是阻塞等待。

一种解决方法,是N个线程竞争一个资源时,启动代理线程代为处理,N个线程向代理线程排队。

EVL { // 这是一个线程实例。当前只使用defer_mgr完成思路展示。
    defer_mgr // defer队列,操作竞争资源,就将请求发送到这个队列即可。

    // timer_mgr // 定时相关的请求,在这里排队。
    // poll_mgr  // sock相关的请求,在这里排队。

    int              exit_req; // 开关。
}

创建EVL:    Evl_Create()
  顶层结构(第一层结构)。
  这是线程的句柄,来自各线程的任务在指定队列排队。

初始化EVL:  Evl_Init(evl)
  创建并初始化 defer_mgr 队列。

启动EVL服务:Evl_Run(evl)
  开启一个线程执行该函数,遍历各队列,有任务则处理。
  调用Evl_ProcessMgrs执行EVL各个队列中任务。
  Evl_Run -- Evl_ProcessMgrs -- DeferMgr_Process

退出EVL:    Evl_Exit(evl)
销毁EVL:    Evl_Destroy(evl)

创建一个defer任务:  EvlDefer_Create(evl, func, arg)
  二层结构。
  创建一个延迟任务,会将任务的执行函数和执行参数放到结构体中。

启动一个defer任务:  EvlDefer_Start(defer)
  即,将该任务让如evl的 defer_mgr 队列。
  EVL服务拿到时间片会自动执行。

销毁一个defer任务:  EvlDefer_Destroy(defer)

USAGE:
  Step 1: 创建一个EVL实例。
    g_evl = Evl_Create();
    Evl_Init(g_evl);  // 创建内部队列。

  Step 2: 创建线程 启动服务。
    pthread_create(&g_thread, NULL, evl_run, (void *)g_evl);
      evl_run:启动EVL服务:Evl_Run(evl);

  Step 3: 创建其他线程,向服务中 push task。
    EvlDefer_t* def = EvlDefer_Create(g_evl, defer_req, transaction);
    EvlDefer_Start(def);

  Step 4: 任务处理函数 处理和释放 defer 资源。
    用户数据:defer->arg
    EvlDefer_Destroy(defer);

【代码实现】

evl_def.h

#ifndef _EVL_DEF__H_
#define _EVL_DEF__H_

#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include "../list/dlist.h"

typedef struct Evl Evl_t;
typedef struct DeferMgr_s DeferMgr_t;
typedef struct EvlDefer_s EvlDefer_t;
typedef void (*EvlDeferFn_t)(EvlDefer_t* defer);

struct Evl {
    DeferMgr_t*      defer_mgr;
    int              exit_req;
};

struct EvlDefer_s  //defer node
{
    ADT_DLIST_DEF(EvlDefer_s);
    EvlDeferFn_t fn;
    void*        arg;
    void*        owner;
    Evl_t*       evl;
};

struct DeferMgr_s {
    EvlDefer_t      head;
    pthread_mutex_t mutex;
};

Evl_t*       Evl_Create(void);
int          Evl_Init(Evl_t* evl);
void         Evl_Exit(Evl_t* evl);
void         Evl_Destroy(Evl_t* evl);

int          Evl_ProcessMgrs(Evl_t* evl);
void         Evl_Run(Evl_t* evl);

EvlDefer_t*  EvlDefer_Create(Evl_t* evl, EvlDeferFn_t fn, void* arg);
void         EvlDefer_Start(EvlDefer_t* defer);
void         EvlDefer_Destroy(EvlDefer_t* defer); 

DeferMgr_t*  DeferMgr_Create(void);
void         DeferMgr_Destroy(DeferMgr_t* obj);
int          DeferMgr_Process(DeferMgr_t* obj, int* rv_more);
EvlDefer_t*  DeferMgr_DeferCreate(Evl_t* evl, EvlDeferFn_t fn, void* arg);
void         DeferMgr_DeferInit(EvlDefer_t* defer, Evl_t* evl, EvlDeferFn_t fn, void* arg);
void         DeferMgr_DeferSetCb(EvlDefer_t* defer, EvlDeferFn_t fn, void* arg);
void         DeferMgr_DeferStart(DeferMgr_t* obj, EvlDefer_t* defer);
void         DeferMgr_DeferStop(DeferMgr_t* obj, EvlDefer_t* defer);
void         DeferMgr_DeferDestroy(DeferMgr_t* obj, EvlDefer_t* defer);

#endif

evl.c

#include "evl_defer.h"

Evl_t* Evl_Create(void)
{
    Evl_t* evl;

    evl = malloc(sizeof *evl);

    if (evl == NULL) {
        return NULL;
    }

    memset(evl, 0, sizeof(*evl));

    return evl;
}

int Evl_Init(Evl_t* evl)
{
    evl->exit_req       = 0;

    if ((evl->defer_mgr = DeferMgr_Create()) == NULL)
        goto fail;

    return 0;

fail:
    Evl_Destroy(evl);
    return -1;
}

void Evl_Destroy(Evl_t* evl)
{
    if (evl->defer_mgr != NULL)
        DeferMgr_Destroy(evl->defer_mgr);

    free(evl);
}

int Evl_ProcessMgrs(Evl_t* evl)
{
    int more_work = 0;
    int run_count = 0;
    if (evl->exit_req)
    {
        return -1;
    }

    do {
	run_count += DeferMgr_Process(evl->defer_mgr, &more_work);
    } while (more_work > 0);

    return run_count;
}

void Evl_Run(Evl_t* evl)
{
    while (!evl->exit_req)
    {
        (void)Evl_ProcessMgrs(evl);
    }
}

void Evl_Exit(Evl_t* evl)
{
    evl->exit_req = 1;
}



EvlDefer_t* EvlDefer_Create(Evl_t* evl, EvlDeferFn_t fn, void* arg)
{
    return DeferMgr_DeferCreate(evl, fn, arg);
}

void EvlDefer_Start(EvlDefer_t* defer)
{
    DeferMgr_DeferStart(defer->evl->defer_mgr, defer);
}

void EvlDefer_Destroy(EvlDefer_t* defer)
{
    DeferMgr_DeferDestroy(defer->evl->defer_mgr, defer);
}

defer.c

//manager
DeferMgr_t* DeferMgr_Create(void)
{
    DeferMgr_t* obj = malloc(sizeof *obj);

    if (obj) {
        ADT_DLIST_HEAD_INIT(&obj->head);
        DeferMgr_DeferSetCb(&obj->head, NULL, NULL);

        pthread_mutex_init(&obj->mutex, NULL);
    }

    return obj;
}

void DeferMgr_Destroy(DeferMgr_t* obj)
{
    if (obj) {
        pthread_mutex_destroy(&obj->mutex);
    }
    free(obj);
}

//consume one item.
int DeferMgr_Process(DeferMgr_t* obj, int* rv_more)
{
    unsigned int count = 0;

    pthread_mutex_lock(&obj->mutex);
    if (ADT_DLIST_IS_EMPTY(&obj->head)) { /?
        pthread_mutex_unlock(&obj->mutex);
        return count;
    }
    EvlDefer_t* entry = ADT_DLIST_NEXT(&obj->head);
    ADT_DLIST_UNLINK(entry);

    pthread_mutex_unlock(&obj->mutex);

    ++count;
    entry->fn(entry);

    const int more = !ADT_DLIST_IS_EMPTY(&obj->head);
    if (rv_more != NULL) {
        *rv_more = more;
    }

    return count;
}

EvlDefer_t* DeferMgr_DeferCreate(Evl_t* evl, EvlDeferFn_t fn, void* arg)
{
    EvlDefer_t* defer = malloc(sizeof *defer);
    if (defer != NULL) {
        DeferMgr_DeferInit(defer, evl, fn, arg);
    }

    return defer;
}

void DeferMgr_DeferInit(EvlDefer_t* defer, Evl_t* evl, EvlDeferFn_t fn, void* arg)
{
    defer->evl = evl;
    ADT_DLIST_NODE_INIT(defer);
    DeferMgr_DeferSetCb(defer, fn, arg);
}

void DeferMgr_DeferSetCb(EvlDefer_t* defer, EvlDeferFn_t fn, void* arg)
{
    defer->fn  = fn;
    defer->arg = arg;
}

void DeferMgr_DeferDestroy(DeferMgr_t* obj, EvlDefer_t* defer)
{
    DeferMgr_DeferStop(obj, defer);
    free(defer);
}

void DeferMgr_DeferStart(DeferMgr_t* obj, EvlDefer_t* defer)
{
    pthread_mutex_lock(&obj->mutex);
    if (!ADT_DLIST_IS_LINKED(defer)) {
        ADT_DLIST_LINK_PREV(&obj->head, defer);
    }
    pthread_mutex_unlock(&obj->mutex);
}

void DeferMgr_DeferStop(DeferMgr_t* obj, EvlDefer_t* defer)
{
    pthread_mutex_lock(&obj->mutex);
    if (ADT_DLIST_IS_LINKED(defer)) {
        ADT_DLIST_UNLINK(defer);
    }
    pthread_mutex_unlock(&obj->mutex);
}

【测试用例】

#include "evl_defer.h"
#include <stdio.h>
#include <unistd.h>

pthread_t g_thread;
Evl_t *g_evl;

void* evl_run(void* arg)
{
    Evl_t* evl = arg;
    Evl_Run(evl);
}

void defer_req(EvlDefer_t* defer)
{
    int *i = defer->arg;
    printf("....... %d \n", *i);

    free(i);
    EvlDefer_Destroy(defer);
}

void test_evl()
{
    int i = 0;

    while (1) {
        int *transaction = malloc(sizeof(int));
        *transaction = i++;

        printf("defer >        %d \n", i);

        EvlDefer_t* def = EvlDefer_Create(g_evl, defer_req, transaction);
        EvlDefer_Start(def);

        sleep(1);
    }
}

int main()
{
    g_evl = Evl_Create();
    Evl_Init(g_evl);

    pthread_create(&g_thread, NULL, evl_run, (void *)g_evl);

    test_evl();

    pthread_join(g_thread, NULL);

    while(1) sleep (10);

    return 0;
}

【测试结果】

gcc main.c defer.c evl.c -lpthread -g

./a.out

[This is work thread, inserting a task]    data:0 
[This is proxy thread, handling a task]    data:0 

[This is work thread, inserting a task]    data:1 
[This is proxy thread, handling a task]    data:1 

[This is work thread, inserting a task]    data:2 
[This is proxy thread, handling a task]    data:2 

[This is work thread, inserting a task]    data:3 
[This is proxy thread, handling a task]    data:3 

[This is work thread, inserting a task]    data:4 
[This is proxy thread, handling a task]    data:4 

[This is work thread, inserting a task]    data:5 
[This is proxy thread, handling a task]    data:5 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值