荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: playboy (冷冷的太阳), 信区: Program
标  题:  Win32 行程通讯的观念与技术(4)
发信站: BBS 荔园晨风站 (Mon Mar 20 15:48:02 2000), 转信

  就像是注册讯息,共享记忆体一样(甚至稍後的Event,MailSlot,Pipe都是),
在我们取得核心物件的Handle前,都是以「名称」叁考的,产生一个Mutex的
API函数是:CreateMutex(), 以下范例采自本文所附的ChienIPC程式单元

constructor TMutex.Create(const name: string);
begin
    FHandle := CreateMutex(
    Nil, // 安全防护属性, 暂时传入nil采用预设值
    False, // 执行绪是否一开始就握有 mutex 的所有权
    pchar(name)); // Mutex核心物件的名称
    if FHandle = 0 then Abort;
end;

    好极了,现在我们有了一个Mutex,该怎麽使用呢? 我用一个情节
来说明:如果一群人在一起开会,每个人桌子前面各摆着一支麦克风
,为了让大家听清楚彼此说什麽,这些麦克风暂时都是关的,规定只
有主席可以透过中央控制系统开启回路。要说话的得先举手表示:
「我要我要」,如果没有别人举手也没人正在发言,主席便打开开
关将发言权交给他,然後这个人的手放下开始讲话。此时若是其他
人也要讲话,根据规则得先举手,在别人讲完交出发言权前只有继
续举手等待的份。当然,排队的人,可以选择手一直举着;或者他
只打算等三分钟,手酸了就放下来。
    执行绪要求拥有Mutex的方法是呼叫WaitForSingleObject()(我
要我要,举手等待),此时程式将暂停(Blocking)在这列。倘若此时
正好没有别的执行绪拥有Mutex (没人讲话),系统会短暂的将Mutex
设为Signaled(激发状态),使得WaitForSingleObject()正常返回,
同时,系统也会将这个Mutex的所有权交给这个执行绪,然後程式继
续执行,握有Mutex所vent(
    LPSECURITY_ATTRIBUTES lpEventAttributes,
    BOOL bManualReset, // flag for manual-reset event
    BOOL bInitialState,// flag for initial state
    LPCTSTR lpName // address of event-object name
);

     同样的,最後一个引数是执行绪在取得Event Handle前叁考同一
Event物件的识别名称,如果相同名称的Event物件稍早已经产生而且
叁用次数尚未归零消灭,并不会多产生一个Event物件,系统只单纯的
将其叁用次数加一,执行绪彼此得以叁考到同一个物件。第三个引数
用来设定Event物件的初值是否为Signaled(激发状态) 。第二个引数
用来设定事件的激发状态是手动或自动;所谓手动与自动的分别在於
事件的状态变成Signaled(激发状态)时,要由系统自动帮我们重设回
非激发状态,或者由程式自行以ResetEvent()将事件设成非激发状态。
    观察DemoSMem的作法是这样的:当某一个行程修改了Shared memory
的内容时,该行程以SetEvent() API 函数将Event物件的状态设为
Signaled(激发状态),叁与行程通讯的各支程式在开跑之初,除了以
相同的识别名称建立(叁用)Event物件之外,还特别分派另一个Thread
专司侦测特定Event物件激发状态的任务,一旦物件激发了,表示一定
某一个行程修改临裎薰亓蔷晒餐窒淼募且涮逵?
Mutex,Event两种同步协调技术,彼此正在密切交换意见。

图: DemoSMem执行情形

MailSlot
    执行DemoSMem时如果让你有广播的感觉,接下来要说的MailSlot
会让你更有广播的感觉,而且它是可以跨越机器边界向网路广播的。

从字面上看来,这像是与寄信有关的通讯机制,实际上它的行为也的
确与其名称相符合。MailSlot就像是你的信箱,只要知道地址,任何
人都可以寄信给你,不过,只有你才可以打开信箱读信。
    MailSlot是一种由系统维护的虚拟档案,建立并拥有Mailslot的
行程扮演Server.的角色,其他的行程包含MailSlot Server本身的行
程均可以开启MailSlot写入讯息,不过,只有MailSlot Server可以
读取资料的内容
。这是个单一Server多个Client的机制,同时,资料只允许由Client
对Server单向传送。
    我想你可能也习惯了,要产生一个MailSlot物件大概也需要一个
识别名称吧! :p 说不定连CreateMailSlot()函数名称都猜得一字不
差。不过,这次的名称可不像先前那样可以随便高兴取什麽就取什麽
的,它具有以下的固定格式:
    \\ServerName\mailslot\[path]name
    我第一次看到时心想: 天哪! 这该怎麽填呀? 边举例边说明会比
较容易懂
    \\.\mailslot\MyMailSlotName MailSlot的识别名称一定从「\\」
双倒斜线开始。接下来的是机器的名称或组群网域的名称,这 的「.」
句号代表的是行程所在的那部机器。再来是「\mailslot」,对於
MailSlot,一定是这个单字照抄就是了。最後则是你自订的MailSlot
名字。先前提到MailSlot实际上是特殊的虚拟档案,所以,要当它
是档名应该也是说得通的。
   的确,援引我们对於档案系统的概念,MailSlot的识别名称就像
路径档名一样,可以经过适当的阶层加分类管理,例如:
\\.\mailslot\Account\Note。最後再看一个例子:
\\*\mailslot\MyMailSlotName,其中「*」指的是群组内的所有机器。
    说得够多了,让我们动手做做看吧! 首先是建立MailSlot Server
的例子,取自本文所附的ChienIPC这个程式单元

procedure TMailSlotServer.Open;
var
    ASlotName: AnsiString;
begin
    if FActive then Exit;
    // 构成 Mailslot 识别名称
    ASlotName := '\\' + FServerName + '\mailslot\' + FSlotName;
    FHandle := CreateMailslot(
        pchar(ASlotName), // MailSlot 识别名称
        0, // 讯息长度的最大值,设为零表示不限
        MAILSLOT_WAIT_FOREVER, // read time-out
        nil); // 安全属性,先暂时采用预设值
    if FHandle = INVALID_HANDLE_VALUE then
        FActive := False
    else
    begin
        FActive := True;
        FWaitThread.Resume;
    end;
end;

    再强调一次,只有MailSlolt Server才可以读取资料,读取的方法
是先以GetMailslotInfo()侦测讯息的长度与数量,然後以回圈逐一配
置记忆体并以ReadFile()读出资料(别忘了MailSlot也是档案),以下
是一则范例:

procedure TMailSlotServer.ReadFromMailSlot;
var
    NextSize: DWORD;
    MessageCount: DWORD;
    Result: BOOL;
    Buffer: pchar;
begin
    if FHandle = INVALID_HANDLE_VALUE then Exit;
    // 侦测 MailSlot 中是否有资料
    Result := GetMailslotInfo(Fhandle, nil,
        NextSize, @MessageCount, nil);
    if not Result or (NextSize = MAILSLOT_NO_MESSAGE) then
        Exit;
    // 如果还有资料 (MessageCount <> 0),逐一读出资料
    while Result and (MessageCount <> 0) do
    begin
        // 资料的长度
        Buffer := AllocMem(NextSize + 1);
        try
            // 读出资料
            FileRead(Fhandle, Buffer^, NextSize);
            if Assigned(FOnDataAvailable) then
            FOnDataAvailable(Self, StrPas(Buffer));
        finally
            FreeMem(Buffer, NextSize + 1);
        end;
        // 继续看看 MailSlot 中还有没有资料
        Result := GetMailslotInfo(Fhandle, nil,
        NextSize, @MessageCount, nil);
    end;
end;

--
※ 来源:·BBS 荔园晨风站 bbs.szu.edu.cn·[FROM: 192.168.1.90]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店