`
zsxxsz
  • 浏览: 455241 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

acl协程中的同步功能

阅读更多

一、概述

    对于 C/C++ 网络协程库,仅提供网络通信功能是远远不够的,如果想要将协程应用于复杂的应用环境中,一些基础性设施是必须的,比如”协程同步“功能。在 acl 协程中,提供了两种应用场景下的同步机制:单机线程内协程之间的同步以及可以跨线程间的协程同步功能。

    因为 acl 协程的调度器是单线程的(如果想用多核,可以启动多个线程,每个线程独立进行调度),所以如果你的应用场景仅需线程内不同协程间的同步,则只需使用 fiber_lock/fiber_sem 即可,其中 fiber_lock 为协程同步锁,fiber_sem 为协程信号量,其实现原理本质上是协程执行上下文的切换,所以比较容易实现;另外,acl 协程还提供应用场景更加复杂应用范围更大的同步的机制,该同步模块支持“协程之间、协程与线程之间、线程之间”的同步,其实现原理是原子操作+IO事件的组合。

 

二、单一线程内协程间的同步

    首先,介绍一下单一线程内协程间的同步接口:fiber_mutex,fiber_rwlock,fiber_sem。其中,fiber_mutex 类似于线程互斥量 pthread_mutex_t,其提供基本的互斥功能,fiber_rwlock 提供协程读写锁功能,fiber_sem 则提供了协程信号量的功能。下面给出一个简单的协程互斥的例子:

 

#include <acl-lib/acl_cpp/lib_acl.hpp>
#include <acl-lib/fiber/libfiber.hpp>

class myfiber : public acl::fiber
{
public:
        myfiber(acl::fiber_mutex& lock) : lock_(lock) {}

protected:
        void run(void)
        {
                for (int i = 0; i < 5; i++) {
                        lock_.lock();
                        printf("locked by fiber-%u and sleep\r\n",
                                acl::fiber::self());
                        sleep(1);
                        printf("fiber-%u wakeup\r\n", acl::fiber::self());
                        lock_.unlock();
                }

                delete this;
        }

private:
        acl::fiber_mutex& lock_;
        ~myfiber(void) {}
};

int main(void)
{
        acl::fiber_mutex lock;

        // 创建并启动第一个协程
        acl::fiber* fb1 = new myfiber(lock);
        fb1->start();

        // 创建并启动第二个协程
        acl::fiber* fb2 = new myfiber(lock);
        fb2->start();

        // 启动协程调度器
        acl::fiber::schedule();

        return 0;
}

 

    该例子非常简单明了的讲述了如何创建 acl 协程,以及如何使用 acl 协程锁进行同步的过程。

 

    该示例代码:https://github.com/acl-dev/demo/blob/master/file_lock.cpp

 

三、协程与线程之间的同步互斥

    acl 协程在最初设计协程同步互斥时,通过上下文切换便很容易实现了,如上面所示,但随着应用场景复杂度的提升,上面的同步方式已经完全不能胜任,在新项目中有一个非常麻烦的处理同步的需求:希望互斥锁不仅可以用在同一线程的协程之间,而且希望还可以用在线程之间,不同线程内的协程之间的同步互斥。因为 acl 的协程调度器是单线程模式,虽然可以同时启动多个线程,每个线程内部创建大量协程,但各个线程之间的资源共享仅能通过系统的线程锁来保证,这看起来似乎没有问题,但却一个场景下完全失效了:

     1、分别创建了 A、B 两类线程,每个线程是一个独立的协程调度过程(即每个线程内可创建大量的协程),同时还创建了 C 线程池(纯线程模式);

     2、A 线程中的某个协程 a1 创建了一个共享对象 o1,协程 a2 创建了一个共享对象 o2;B 线程中的某个协程 b1 创建一个共享对象 o3;

     3、a1 协程对 o1 加锁保护,a2 协程对 o2 加锁保护,b1 协程对 o3 加锁保护;

     4、在某一时刻,b1 协程因想要对 o2 加锁保护而处于等待状态,但此时恰巧 a1 协程想要对 o3 加锁,但此时 o3 已被 b1 协程加锁保护。

 

    针对上述过程,如果用纯线程锁进行加锁保护则肯定会出现死锁问题,因此在 acl 协程里设计了一个可在不同线程的协程间共享的事件互斥模块:fiber_event(C++类)或 acl_fiber_event(C语言)。在此暂且不讲该功能实现(实现有点复杂且有一定技巧性),只讲如何使用,下面是 fiber_event 提供的功能接口:

 

/**
 * 可用于协程之间、线程之间以及协程与线程之间,通过事件等待/通知方式进行同步的
 * 的事件混合锁
 */
class fiber_event
{
public:
	/**
	 * 构造方法
	 * @param use_mutex {bool} 在用在多线程之间进行事件同步时,如果启动的
	 *  的线程数较多(成百上千个线程),则此标志应设为 true 以便于内部在
	 *  同步内部对象时使用线程互斥锁进行保护,以避免形成惊群现象,如果启动
	 *  的线程数较多但该标志为 false,则内部使用原子数进行同步保护,很容易
	 *  造成惊群问题;当启动的线程数较(几十个左右),则此参数可以设为 false
	 *  以告之内部使用原子数进行同步保护
	 * @param fatal_on_error {bool} 内部发生错误时是否直接崩溃,以便于开发
	 *  人员进行错误调试
	 */
	fiber_event(bool use_mutex = true, bool fatal_on_error = true);
	~fiber_event(void);

	/**
	 * 等待事件锁
	 * @return {bool} 返回 true 表示加锁成功,否则表示内部出错
	 */
	bool wait(void);

	/**
	 * 尝试等待事件锁
	 * @return {bool} 返回 true 表示加锁成功,否则表示锁正在被占用
	 */
	bool trywait(void);

	/**
	 * 事件锁拥有者释放事件锁并通知等待者
	 * @return {bool} 返回 true 表示通知成功,否则表示内部出错
	 */
	bool notify(void);

public:
	/**
	 * 返回 C 版本的事件对象
	 * @return {ACL_FIBER_EVENT*}
	 */
	ACL_FIBER_EVENT* get_event(void) const
	{
		return event_;
	}

private:
	ACL_FIBER_EVENT* event_;
};

 

 

     接下来给出一个简单的例子:

 

#include <acl-lib/acl_cpp/lib_acl.hpp>
#include <acl-lib/fiber/libfiber.hpp>

class myfiber : public acl::fiber
{
public:
        myfiber(acl::fiber_event& event, unsigned long long& count)
        : event_(event)
        , count_(count)
        {}

protected:
        // @override
        void run(void)
        {
                for (int i = 0; i < 1000; i++) {
                        event_.wait();
                        count_++;
                        if (count_ % 100000 == 0) {
                                printf("thread-%ld, fiber-%u, count=%llu\r\n",
                                        acl::thread::self(), acl::fiber::self(),
                                        count_);
                        }
                        event_.notify();
                }

                delete this;
        }

private:
        acl::fiber_event& event_;
        unsigned long long& count_;

        ~myfiber(void) {}
};

class mythread : public acl::thread
{
public:
        mythread(acl::fiber_event& event, unsigned long long& count)
        : event_(event)
        , count_(count)
        {}

        ~mythread(void) {}

protected:
        // @override
        void* run(void)
        {
                for (int i = 0; i < 1000; i++) {
                        acl::fiber* fb = new myfiber(event_, count_);
                        fb->start();
                }

                acl::fiber::schedule();
                return NULL;
        }

private:
        acl::fiber_event& event_;
        unsigned long long& count_;
};

int main(void)
{
        unsigned long long count = 0;
        acl::fiber_event event;

        std::vector<acl::thread*> threads;
        for (int i = 0; i < 10; i++) {
                acl::thread* thr = new mythread(event, count);
                threads.push_back(thr);
                thr->start();
        }

        for (std::vector<acl::thread*>::iterator it = threads.begin();
                it != threads.end(); ++it) {
                (*it)->wait();
                delete *it;
        }

        printf("at last count=%llu\r\n", count);
        return 0;
}

 

 

    在上面例子中,创建 10 个线程,每个线程是一个独立的协程调度过程;每个线程内部创建 1000 个协程,每个协程内部对全局对象 count 进行加 1 操作,每次对 count 加 1 都需要调用 acl::thread_event 中的 wait/notify 进行同步。

    该示例代码:https://github.com/acl-dev/demo/blob/master/fiber_event.cpp

分享到:
评论

相关推荐

    CC服务器和网络库,包括coroutineredis clienthttphttpswebsocketmqtt mys.zip

    这套库中的coroutine支持了协程的使用,使得网络编程更加高效和简洁。redis client指的是客户端组件,它实现了与Redis服务器之间的通信,Redis是一个开源的使用内存存储数据的高性能数据库。clienthttp和clienthttps...

    ### 2024年第一季度青岛房地产市场季度简报总结、市场综述

    2024年第一季度,青岛房地产市场经历了显著变化,总体呈现供需双降的趋势。一季度全市商品房新增10,721套,面积约152.04万平方米,同比下降29%;销量为14,936套,面积约200.85万平方米,同比下降38%,成交均价为14,204元/平方米,同比下降2%。土地市场方面,供应总量为39万平方米,同比减少7%,但成交面积为27万平方米,同比增长31%,楼面地价为6,625元/平方米,同比增长253%,土地出让金为17.61亿元,同比增长354%。二手房市场新增挂牌2.9万套,成交13,405套,132.21万平方米,累计挂牌51.70万套,挂牌均价17,800元/平方米。此外,青岛市出台多项政策支持房地产市场平稳健康发展,包括降低房贷利率、优化开发用地土地规划政策、支持房企融资等。这些政策旨在促进市场供需平衡,防止市场大起大落。

    Linux常用命令大全.markdown

    linux常用命令大全

    MATLAB代码,用于模拟具有无限半空间体积导体的电机单元电势(MUP),星号.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    空调销售网站策划案例.doc

    空调销售网站策划案例.doc

    全球6G技术大会2024年以用户为中心的6G接入网技术研究白皮书31页.pdf

    全球6G技术大会2024年以用户为中心的6G接入网技术研究白皮书31页.pdf

    简约专业风格毕业答辩模板47个

    简约专业风格毕业答辩模板是一系列专为追求简洁与高效表达的大学生设计的答辩文档模板,共47个。这些模板融合了经典的设计元素与现代审美,强调信息的清晰传递与视觉的整洁,旨在帮助学生在答辩中以最专业的面貌展示自己的研究成果。 每个模板都具备结构合理的布局,适用于各个学科和研究领域,从人文社科到自然科学,均能满足不同需求。简约风格的设计使得学生能够专注于内容本身,避免冗余信息的干扰,提升答辩的专业性和可信度。此外,模板中合理运用的色彩、字体和图表设计,不仅增强了视觉吸引力,也使信息更易于理解。 通过使用这些简约专业风格的毕业答辩模板,毕业生能够自信地呈现自己的学术成果,提升答辩的整体效果,为成功的学术交流打下坚实基础。这些模板是展示个人研究与风格的理想选择。

    【数据集和模型】ChatGPT文本二分类

    由 Epsilon Luoo 在 HC3-Chinese 的基础上进行了一些细微的修改和清洗

    数字人动作捕捉:MATLAB-Kinect骨骼数据实时插值算法.pdf

    文档支持目录章节跳转同时还支持阅读器左侧大纲显示和章节快速定位,文档内容完整、条理清晰。文档内所有文字、图表、函数、目录等元素均显示正常,无任何异常情况,敬请您放心查阅与使用。文档仅供学习参考,请勿用作商业用途。 你是否渴望高效解决复杂的数学计算、数据分析难题?MATLAB 就是你的得力助手!作为一款强大的技术计算软件,MATLAB 集数值分析、矩阵运算、信号处理等多功能于一身,广泛应用于工程、科学研究等众多领域。 其简洁直观的编程环境,让代码编写如同行云流水。丰富的函数库和工具箱,为你节省大量时间和精力。无论是新手入门,还是资深专家,都能借助 MATLAB 挖掘数据背后的价值,创新科技成果。别再犹豫,拥抱 MATLAB,开启你的科技探索之旅!

    HI3519DV500 配置无线网依赖库以及编译脚本

    HI3519DV500 配置无线网依赖库以及编译脚本

    定制小米8-lineage22.1安卓15-fast功能项目线刷双版root 解锁bl后fast线刷

    资源说明; 1-----刷写前提是手机必须解锁bl先。而且会在fast模式刷写固件 2-----刷写方法与官方刷写步骤一样 3-----此固件为定制初始固件。可以在fast模式刷写 4-----属于适配固件。也许有个别bug。不接受请勿下载 5-----需要一定的刷机常识与动手能力的友友刷写。 6-----资源有可复制性。下载后不支持退。请知悉 7-----定制其他需求可以在csdn私信博主 博文参阅:https://csdn9.blog.csdn.net/article/details/143058308

    【机械臂路径规划】基于matlab快速探索随机树RRT和概率路网PRM串联机械臂路径规划【含Matlab源码 13167期】.zip

    Matlab领域上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作

    世邦魏理仕:2021年西安房地产市场回顾与2022年展望.pdf

    世邦魏理仕:2021年西安房地产市场回顾与2022年展望

    Android Studio 2022.1.1和java编程语言yinyuebofangqi.zip

    Android Studio 2022.1.1和java编程语言yinyuebofangqi

    C知道对话分享图片下载

    C知道对话分享图片

    png-jpg-gif-webp-tiff等图片压缩工具基于nodejs的实现

    png-jpg-gif-webp-tiff等图片压缩工具基于nodejs的实现,绿色本地免安装,解压后运行exe文件,将图片文件或者包含图片的文件夹拖拽到软件界面即可压缩

    派对屋A1效果器电脑调音软件

    我们要了解什么是DSP(Digital Signal Processing)。DSP即数字信号处理,是一种利用数字计算方法对信号进行分析、变换和操作的技术。在汽车音响领域,DSP被广泛应用于改善音质,通过调整频率响应、延时、相位和增益等参数,使声音更加均衡、立体。 惠威是一款数字信号处理器,适用于那些希望升级原车音响系统但预算有限的用户。它通常拥有多个输入和输出接口,可以连接到汽车的音频源和扬声器,通过软件进行调音,使得声音能够适应不同的驾驶环境和听音偏好。 ,集成了先进的噪声抑制技术和强大的功率放大器,旨在为发烧友级别的车载音响系统提供卓越的性能。用户可以通过软件对整个系统的每一个细节进行优化,包括主动分频、时间校正等,以达到Hi-Fi级别的音乐享受。

    通信工程分包合同.docx

    通信工程分包合同.docx

    demo1(1).py

    demo1(1).py

    金融量化交易:MATLAB_构建多因子选股模型的完整开发指南.pdf

    文档支持目录章节跳转同时还支持阅读器左侧大纲显示和章节快速定位,文档内容完整、条理清晰。文档内所有文字、图表、函数、目录等元素均显示正常,无任何异常情况,敬请您放心查阅与使用。文档仅供学习参考,请勿用作商业用途。 你是否渴望高效解决复杂的数学计算、数据分析难题?MATLAB 就是你的得力助手!作为一款强大的技术计算软件,MATLAB 集数值分析、矩阵运算、信号处理等多功能于一身,广泛应用于工程、科学研究等众多领域。 其简洁直观的编程环境,让代码编写如同行云流水。丰富的函数库和工具箱,为你节省大量时间和精力。无论是新手入门,还是资深专家,都能借助 MATLAB 挖掘数据背后的价值,创新科技成果。别再犹豫,拥抱 MATLAB,开启你的科技探索之旅!

Global site tag (gtag.js) - Google Analytics