IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> Workflow(6) -> 正文阅读

[数据结构与算法]Workflow(6)

2021SC@SDUSC

? ? ? ? 继续上一篇博客分析,这里用到了红黑树来组织数据,之前在数据结构课程中并没有详细讲解。红黑树在二叉查找树的基础上,增加了一些额外要求:它的根结点必须是黑色;所有叶子结点也是黑色;每个红色节点的两个结节点都是黑色,即从每个叶子到根的路径上不能有两个连续的红色结点;从任一结点到每个叶子的所有路径都包含相同数目的黑色节点。

? ? ? ? ?这些约束是的红黑树从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。在进行插入、删除和查找某个值等操作的最坏情况下它也是高效的。

struct rb_node
{
	struct rb_node *rb_parent;
	struct rb_node *rb_right;
	struct rb_node *rb_left;
	char rb_color;
#define	RB_RED		0
#define	RB_BLACK	1
};

? ? ? ?红黑树结点的定义在src/kernel/rbtree.h中,每个结点有指向父节点、左子节点、右子节点的指针,还增加了对结点颜色的描述来保持操作的高效性。

class WFNSPolicy
{
public:
	virtual WFRouterTask *create_router_task(const struct WFNSParams *params,
											 router_callback_t callback) = 0;

	virtual void success(RouteManager::RouteResult *result,
						 WFNSTracing *tracing,
						 CommTarget *target)
	{
		RouteManager::notify_available(result->cookie, target);
	}

	virtual void failed(RouteManager::RouteResult *result,
						WFNSTracing *tracing,
						CommTarget *target)
	{
		if (target)
			RouteManager::notify_unavailable(result->cookie, target);
	}

public:
	virtual ~WFNSPolicy() { }
};

? ? ? ? ? WFNameService类中有变量RWlock,它定义在src/util/RWLock.h中,利用信号量和条件变量来实现锁,在多线程情况下,保证数据的正确性与一致性。wlock()获得锁,unlock()释放锁。

class WFNameService
{
public:
	int add_policy(const char *name, WFNSPolicy *policy);
	WFNSPolicy *get_policy(const char *name);
	WFNSPolicy *del_policy(const char *name);

private:
	WFNSPolicy *default_policy;
	struct rb_root root;
	RWLock rwlock;

private:
	struct WFNSPolicyEntry *get_policy_entry(const char *name);

public:
	WFNameService(WFNSPolicy *default_policy)
	{
		this->root.rb_node = NULL;
		this->default_policy = default_policy;
	}
};

? ? ? ? ?再看看add_policy()方法的实现代码,while循环寻找应该插入结点的地方,类似二叉树的操作,比较要插入的name和红黑树里结点的name的大小,如果要插入的小,就应该往左子节点继续深入,反之往右节点继续。需要用malloc为新结点开辟一块内存空间,以及确定节点是红色还是黑色,保证从每个叶子到根的路径上不能有两个连续的红色结点;从任一结点到每个叶子的所有路径都包含相同数目的黑色节点。

int WFNameService::add_policy(const char *name, WFNSPolicy *policy)
{
	struct rb_node **p = &this->root.rb_node;
	struct rb_node *parent = NULL;
	struct WFNSPolicyEntry *entry;
	int n, ret = -1;

	this->rwlock.wlock();
	while (*p)
	{
		parent = *p;
		entry = rb_entry(*p, struct WFNSPolicyEntry, rb);
		n = strcasecmp(name, entry->name);
		if (n < 0)
			p = &(*p)->rb_left;
		else if (n > 0)
			p = &(*p)->rb_right;
		else
			break;
	}

	if (!*p)
	{
		size_t len = strlen(name);
		size_t size = offsetof(struct WFNSPolicyEntry, name) + len + 1;

		entry = (struct WFNSPolicyEntry *)malloc(size);
		if (entry)
		{
			memcpy(entry->name, name, len + 1);
			entry->policy = policy;
			rb_link_node(&entry->rb, parent, p);
			rb_insert_color(&entry->rb, &this->root);
			ret = 0;
		}
	}
	else
		errno = EEXIST;

	this->rwlock.unlock();
	return ret;
}

? ? ? 这里的inline将get_policy_entry()指定为内联函数,解决一些频繁调用的函数大量消耗栈空间的问题。函数的逻辑比较便于理解,与二叉树的查找操作十分类似。

inline struct WFNSPolicyEntry *WFNameService::get_policy_entry(const char *name)
{
	struct rb_node *p = this->root.rb_node;
	struct WFNSPolicyEntry *entry;
	int n;

	while (p)
	{
		entry = rb_entry(p, struct WFNSPolicyEntry, rb);
		n = strcasecmp(name, entry->name);
		if (n < 0)
			p = p->rb_left;
		else if (n > 0)
			p = p->rb_right;
		else
			return entry;
	}

	return NULL;
}

? ? ? ? ?这里的get_policy(const char *name)、del_policy(const char *name)方法都需要调用上面的:get_policy_entry(const char *name),代码逻辑也不难理解,根据key值name,在红黑树中找到对应的结点。

WFNSPolicy *WFNameService::get_policy(const char *name)
{
	WFNSPolicy *policy = this->default_policy;
	struct WFNSPolicyEntry *entry;

	this->rwlock.rlock();
	entry = this->get_policy_entry(name);
	if (entry)
		policy = entry->policy;

	this->rwlock.unlock();
	return policy;
}

WFNSPolicy *WFNameService::del_policy(const char *name)
{
	WFNSPolicy *policy = NULL;
	struct WFNSPolicyEntry *entry;

	this->rwlock.wlock();
	entry = this->get_policy_entry(name);
	if (entry)
	{
		policy = entry->policy;
		rb_erase(&entry->rb, &this->root);
	}

	this->rwlock.unlock();
	free(entry);
	return policy;
}


?

参考资料:

(60条消息) [linux,kernel,rbtree] rb_node 结构体分析_inuyasha1027的专栏-CSDN博客

红黑树_百度百科 (baidu.com)

面试:各种锁的实现原理 - 简书 (jianshu.com)

C++ inline内联函数详解 (biancheng.net)

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章           查看所有文章
加:2021-11-30 15:52:09  更:2021-11-30 15:54:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 13:49:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码