一个完整的OTP应用简例

    以前研读过一次Erlang OTP框架,但总觉得理解还不够,没有亲手实现一个应用。纸上得来终觉浅,绝知此事须躬行。:)

    近日恰好有时间,又把Erlang OTP框架拿来研读,并尝试完成了一个简单的用OTP实现的应用。本应用同时实现了一个事件管理器及相关测试代码。

    应用实例中实现的行为模式包括application、supervisor、gen_server、gen_event,实现的简单功能是定制事件管理器来实现事件日志,可以添加和删除事件管理器,并使用自定义的事件管理器输出事件日志,使用应用来启动监督进程,利用监督进程管理普通服务器和事件管理器的进程。

    应用实例的主要模块包括:event_app(实现application)、root_sup(实现supervisor)、myserv(实现gen_server)、event_mod(实现gen_event)。应用的目录结构也采取最简单的形式,即项目主目录下仅有两个子目录:ebin 和 src。

    其基本代码如下:

%filename event_app.app

%应用资源文件
{application, event_app,
[{description,"a simple logger."},
{vsn,"1.0"},
{modules,[event_mod,root_sup,event_app,myserv]},
{registered,[event_mod,root_sup,myserv]},
{applications,[kernel,stdlib]},
{mod,{event_app,[]}}]}.     %%指明应用启动模块

%filename event_app.erl

-module (event_app).
-behaviour (application).  %%实现应用行为
-compile(export_all).

start(_Type,_StartArgs) ->
    case root_sup:start_link() of
        {ok,Pid} -> {ok,Pid};
        Other ->
            {error,Other}
    end.

stop(_State) -> ok.

%filename root_sup

-module (root_sup).
-behaviour (supervisor).  %%实现监督者行为
-compile(export_all).

start_link() ->
    supervisor:start_link({local,?MODULE},?MODULE,[]).

init([]) ->
    Event = {event_mod,{event_mod,start_link,[]},
        permanent,2000,worker,[event_mod]},
    Myserv = {myserv,{myserv,start_link,[]},
        permanent,2000,worker,[myserv]},
    Children = [Event,Myserv],
    RestartStrategy = {one_for_one,0,1},
    {ok,{RestartStrategy,Children}}.      %%返回监控进程规范和子进程规范列表
%filename myserv.erl

-module (myserv).
-behaviour (gen_server).
-compile(export_all).

start_link() ->
    gen_server:start_link({local,?MODULE},?MODULE,[],[]).

init([]) ->{ok,[]}.

add_hdl() ->       %%添加自定义事件处理器(用户API)
    gen_server:cast(?MODULE,addhdl).
del_hdl() ->       %%删除自定义事件处理器(用户API)
    gen_server:cast(?MODULE,delhdl).

log_test() ->      %%引发日志事件测试
    event_mod:log_test().  %%通过调用委托给event_mod模块

handle_cast(addhdl,State) ->
    event_mod:add_handler(),   %%通过调用委托给event_mod模块
    {noreply,State};
handle_cast(delhdl,State) ->
    event_mod:del_handler(),   %%通过调用委托给event_mod模块
    {noreply,State}.

%%其它消息不作处理
handle_call(_,_,State) -> {reply,{ok,ok},State}.
handle_info(_,State) -> {noreply,State}.
code_change(_OldVsn,State,_Extra) -> {ok,State}.
terminate(_,_) -> ok.

%filename event_mod.erl

-module (event_mod).
-compile(export_all).
-behaviour (gen_event).   %%实现事件管理器行为

start_link() ->
    gen_event:start_link({local,?MODULE}).

init([]) -> {ok,[]}.

add_handler() ->          %%添加事件管理器
    gen_event:add_handler(?MODULE,?MODULE,[]).

delete_handler() ->       %%删除事件管理器
    gen_event:delete_handler(?MODULE,?MODULE,[]).

log_test() ->             %%引发日志事件测试函数
    gen_event:notify(?MODULE,test).  %%引发日志事件

handle_event(test,State) ->          %%引发日志事件的处理函数
    error_logger:info_msg("Test send up.~n"),
    {ok,File} = file:open("aqw.txt",write),  %%可将相关日志信息写入指定文件,实际程序中文件名不会硬编码
    io:format(File,"aqwkdkkdkd~n",[]),
    file:close(File),
    {ok,State};
handle_event(_Msg,State) ->
    {ok,State}.

运行测试结果如下图:


<think>我们被要求提供一个DirectComposition集成Direct2D的单示。根据之前的讨论,DirectComposition需要Direct2D来生成内容,然后将内容绑定到DirectComposition的视觉树上进行合成和动画。 我们将使用C++来编写示,因为这是使用DirectX API最直接的方式。示将包括以下步骤: 1. 初始化Direct2D和DirectComposition所需的基本组件。 2. 创建Direct2D渲染目标(与DirectComposition表面关联)。 3. 使用Direct2D绘制内容。 4. 创建DirectComposition视觉树并将绘制的内容附加到视觉上。 5. 将视觉树连接到窗口。 注意:为了化,我们省略了错误检查和资源释放的部分(在实际代码中必须处理)。 步骤详解: 1. 初始化: - 创建Direct2D工厂(ID2D1Factory)。 - 创建DirectComposition设备(IDCompositionDevice)和桌面目标(IDCompositionTarget)。 2. 创建渲染目标: - 使用DirectComposition创建一个表面(IDCompositionSurface)。 - 使用该表面创建Direct2D渲染目标(ID2D1RenderTarget)。 3. 绘制: - 在渲染目标上开始绘制。 - 绘制一些图形(如矩形、文本等)。 - 结束绘制。 4. 创建视觉树: - 创建一个DirectComposition视觉(IDCompositionVisual)。 - 将表面设置为该视觉的内容。 - 设置视觉的位置等属性(可选)。 - 创建视觉树(将视觉添加到根或其他视觉)。 5. 连接到窗口: - 将根视觉设置为桌面目标的内容。 - 提交DirectComposition批次。 下面是一个化的代码示: 注意:此示假设你已经有一个窗口(HWND)来绑定。 我们将创建一个函数,该函数在窗口创建后调用,用于初始化Direct2D和DirectComposition,并绘制一个单的矩形。</think>### DirectComposition 集成 Direct2D 的单示 以下是一个的 C++ 示,展示如何将 Direct2D 渲染的内容集成到 DirectComposition 视觉树中。代码基于 Windows API 实现,核心步骤已添加注释说明: ```cpp #include <dcomp.h> #include <d2d1_1.h> #include <d2d1_1helper.h> #include <wrl/client.h> using namespace Microsoft::WRL; // 1. 初始化组件 ComPtr<ID2D1Factory1> d2dFactory; ComPtr<IDCompositionDevice> dcompDevice; ComPtr<IDCompositionTarget> dcompTarget; // 创建 Direct2D 工厂 (内容生成器) D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, d2dFactory.GetAddressOf()); // 创建 DirectComposition 设备 (合成器) DCompositionCreateDevice(nullptr, IID_PPV_ARGS(&dcompDevice)); // 2. 创建渲染目标 ComPtr<IDCompositionSurface> surface; dcompDevice->CreateSurface(400, 300, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_ALPHA_MODE_PREMULTIPLIED, &surface); // 获取 Direct2D 渲染目标 POINT offset; ComPtr<ID2D1DeviceContext> d2dContext; surface->BeginDraw(nullptr, IID_PPV_ARGS(&d2dContext), &offset); // 3. 使用 Direct2D 绘制内容 d2dContext->BeginDraw(); d2dContext->Clear(D2D1::ColorF(D2D1::ColorF::LightBlue)); // 蓝色背景 // 绘制红色矩形 ComPtr<ID2D1SolidColorBrush> brush; d2dContext->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Red), &brush); d2dContext->FillRectangle(D2D1::RectF(50, 50, 350, 250), brush.Get()); d2dContext->EndDraw(); surface->EndDraw(); // 4. 构建视觉树 ComPtr<IDCompositionVisual> visual; dcompDevice->CreateVisual(&visual); visual->SetContent(surface.Get()); // 将 Direct2D 内容绑定到视觉 // 5. 设置窗口目标 (假设 hwnd 是有效窗口句柄) dcompDevice->CreateTargetForHwnd(hwnd, TRUE, &dcompTarget); dcompTarget->SetRoot(visual.Get()); // 设置根视觉 // 6. 提交合成 dcompDevice->Commit(); // 更新屏幕显示 ``` ### 关键步骤说明: 1. **资源初始化** - `ID2D1Factory` 创建 Direct2D 绘图资源[^1] - `IDCompositionDevice` 管理合成管道 2. **内容绑定** - `IDCompositionSurface` 作为 Direct2D 和 DirectComposition 的共享表面 - 通过 `BeginDraw()`/`EndDraw()` 实现 GPU 零拷贝数据传输[^2] 3. **视觉树构建** - `IDCompositionVisual` 承载渲染内容 - `SetContent()` 将 Direct2D 输出附加到视觉节点 4. **窗口集成** - `CreateTargetForHwnd()` 将视觉树绑定到窗口 - `Commit()` 触发 GPU 合成操作 > ⚡ **性能优势**:整个流程在 GPU 内完成,避免了 CPU-GPU 数据传输瓶颈。测试表明,相比 GDI 方案,动画帧率可提升 3-5 倍[^3]。 --- ### 相关问题 1. DirectComposition 如何实现 60FPS 流畅动画? 2. 在 UWP 应用中集成 DirectComposition 有哪些注意事项? 3. 如何通过 DirectComposition 实现图层的 3D 变换效果? 4. Direct2D 与 DirectWrite 如何协同工作实现高质量文本渲染? 5. 调试 DirectComposition 合成问题的常用工具有哪些?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值