前言
本文記錄通過回調函數通知到多線程的框架。
本文鏈接:李柱明博客-框架:https://www.cnblogs.com/lizhuming/p/15205560.html
主要用於解耦。
實現原理
就是把多個回調函數插入到一個鏈表中,在對應的地方執行這個鏈表中的所有回調函數。
用途
通知業務只是該原理的作用之一,更多用途由用戶自由發揮。
用途之一的通知:各個業務組建一個回調函數,其內容主要是發送消息或其它 IPC。把業務通知到對應線程去執行。
也可以點到點通知,底層功能通過 ID 區分業務,找到該業務綁定在該功能的回調函數執行。
通知結構體源碼
以下結構體可以按需求修改。
struct notifier {
struct notifier *next;
notify_func func;
void *arg;
};
鏈表管理
采用單向鏈表管理同一類回調函數。
函數類型
可以按需求修改。
typedef void (*notify_func)(void *, int type, int value);
注冊&注銷
注冊:創建一個通知結構體作為節點,配置好參數。插入單向鏈表中。
注銷:從鏈表中刪除節點,釋放通知結構體。
使用
函數就是 void notify(struct notifier *notif, int type, int val)
。
調用該函數把鏈表 notif
上的回調函數都執行一遍。
參考源碼
底層文件,實現注冊和注銷
/** @file lzm_notifier.c
* @brief 簡要說明
* @details 詳細說明
* @author lzm
* @date 2021-09-01 12:10:06
* @version v1.1
* @copyright Copyright By lizhuming, All Rights Reserved
* @blog https://www.cnblogs.com/lizhuming/
*
**********************************************************
* @LOG 修改日志:
* v1.1 add lock
**********************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lzm_notifier.h"
/**
* @name add_notifier
* @brief add a new function to be called when something happens.
* @param
* @retval
* @author lzm
*/
int add_notifier(notifier_ctx_t *notifier_ctx_ptr, notify_func func, void *arg)
{
if(notifier_ctx_ptr == NULL || func == NULL)
return -1;
notifier_t *np = NULL;
pthread_mutex_lock(¬ifier_ctx_ptr->lock);
for(np = notifier_ctx_ptr->notif; np != NULL; np = np->next)
{
if(np->func == func && np->arg == arg)
{
pthread_mutex_unlock(¬ifier_ctx_ptr->lock);
return 0; // already exist
}
}
np = (notifier_t *)malloc(sizeof(notifier_t));
if (np == NULL)
{
pthread_mutex_unlock(¬ifier_ctx_ptr->lock);
printf("no mem\n");
return -1;
}
np->next = notifier_ctx_ptr->notif;
np->func = func;
np->arg = arg;
notifier_ctx_ptr->notif = np;
pthread_mutex_unlock(¬ifier_ctx_ptr->lock);
return 0;
}
/**
* @name add_notifier
* @brief remove a function from the list of things to be called when something happens.
* @param
* @retval
* @author lzm
*/
int remove_notifier(notifier_ctx_t *notifier_ctx_ptr, notify_func func, void *arg)
{
if(notifier_ctx_ptr == NULL || notifier_ctx_ptr->notif == NULL || func == NULL)
return -1;
notifier_t *np = NULL;
notifier_t *np_last = NULL;
pthread_mutex_lock(¬ifier_ctx_ptr->lock);
np_last = notifier_ctx_ptr->notif;
np = notifier_ctx_ptr->notif;
while(1)
{
if (np->func == func && np->arg == arg)
{
if(np_last == np)
notifier_ctx_ptr->notif =np->next;
else
np_last->next = np->next;
free(np);
break;
}
if(np->next == NULL)
break;
np_last = np;
np = np->next;
}
pthread_mutex_unlock(¬ifier_ctx_ptr->lock);
return 0;
}
/**
* @name notify
* @brief call a set of functions registered with add_notify. (執行該單向鏈表中的所有回調函數)
* @param
* @retval
* @author lzm
*/
int notify(notifier_ctx_t *notifier_ctx_ptr, int type, int val)
{
if(notifier_ctx_ptr == NULL)
return -1;
notifier_t *np = NULL;
pthread_mutex_lock(¬ifier_ctx_ptr->lock);
np = notifier_ctx_ptr->notif;
while (np != NULL)
{
(*np->func)(np->arg, type, val);
np = np->next;
}
pthread_mutex_unlock(¬ifier_ctx_ptr->lock);
return 0;
}
/**
* @name notify_init
* @brief 入口func
* @param
* @retval
* @author lzm
*/
int notify_init(notifier_ctx_t *notifier_ctx_ptr)
{
if(notifier_ctx_ptr != NULL)
return -1;
notifier_ctx_ptr = malloc(sizeof(notifier_ctx_t));
if(notifier_ctx_ptr == NULL)
return -2;
memset(notifier_ctx_ptr, 0x00, sizeof(notifier_ctx_t));
pthread_mutex_init(¬ifier_ctx_ptr->lock, NULL);
pthread_mutex_lock(¬ifier_ctx_ptr->lock);
notifier_ctx_ptr->notif = NULL;
pthread_mutex_unlock(¬ifier_ctx_ptr->lock);
return 0;
}
/**
* @name notify_exit
* @brief 出口func
* @param
* @retval
* @author lzm
*/
int notify_exit(notifier_ctx_t *notifier_ctx_ptr)
{
if(notifier_ctx_ptr == NULL)
return -1;
notifier_t *np = NULL;
notifier_t *np_next = NULL;
/* exit notify */
notify(notifier_ctx_ptr, 0, 0);
pthread_mutex_lock(¬ifier_ctx_ptr->lock);
np = notifier_ctx_ptr->notif;
while (np != NULL)
{
np_next = np->next;
free(np);
np = np_next;
}
notifier_ctx_ptr->notif = NULL;
pthread_mutex_unlock(¬ifier_ctx_ptr->lock);
pthread_mutex_destroy(¬ifier_ctx_ptr->lock);
free(notifier_ctx_ptr);
return 0;
}
/* 以下為 demo API, 放到其它文件 */
notifier_ctx_t *lzm_notifier_ctx = NULL;
/**
* @name lzm_register_notifier
* @brief
* @param
* @retval
* @author lzm
*/
int lzm_register_notifier(notify_func func, void *arg)
{
return add_notifier(lzm_notifier_ctx, func, arg);
}
/**
* @name lzm_remove_notifier
* @brief api
* @param
* @retval
* @author lzm
*/
void lzm_remove_notifier(notify_func func, void *arg)
{
remove_notifier(lzm_notifier_ctx, func, arg);
}
/**
* @name lzm_notify
* @brief api
* @param
* @retval
* @author lzm
*/
void lzm_notify(int type, int val)
{
notify(lzm_notifier_ctx, type, val);
}
/**
* @name lzm_notify_init
* @brief api
* @param
* @retval
* @author lzm
*/
void lzm_notify_init(void)
{
notify_init(lzm_notifier_ctx);
}
/**
* @name lzm_notify_exit
* @brief api
* @param
* @retval
* @author lzm
*/
void lzm_notify_exit(void)
{
notify_exit(lzm_notifier_ctx);
}
接口文件
/** @file lzm_notifier.h
* @brief 簡要說明
* @details 詳細說明
* @author lzm
* @date 2021-09-01 12:10:06
* @version v1.1
* @copyright Copyright By lizhuming, All Rights Reserved
* @blog https://www.cnblogs.com/lizhuming/
*
**********************************************************
* @LOG 修改日志:
* v1.1 add lock
**********************************************************
*/
#ifndef __lzm_notifier_h__
#define __lzm_notifier_h__
#include <pthread.h>
typedef void (*notify_func)(void *, int type, int value);
struct notifier
{
struct notifier *next;
notify_func func;
void *arg;
};
typedef struct notifier notifier_t;
typedef struct
{
pthread_mutex_t lock;
notifier_t *notif;
}notifier_ctx_t;
int add_notifier(notifier_ctx_t *notifier_ctx_ptr, notify_func func, void *arg);
int remove_notifier(notifier_ctx_t *notifier_ctx_ptr, notify_func func, void *arg);
int notify(notifier_ctx_t *notifier_ctx_ptr, int type, int val);
int notify_init(notifier_ctx_t *notifier_ctx_ptr);
int notify_exit(notifier_ctx_t *notifier_ctx_ptr);
/* 以下為demo API, 放到其它文件 */
int lzm_register_notifier(notify_func func, void *arg);
void lzm_remove_notifier(notify_func func, void *arg);
void lzm_notify(int type, int val);
void lzm_notify_init(void);
void lzm_notify_exit(void);
#endif /* Head define end*/