使用setjmp / longjmp的通信协议和本地环回

时间:2016-09-20 20:42:13

标签: c++ ipc setjmp

我使用共享内存和共享互斥锁编写了一些相对简单的通信协议。但后来我想扩大支持,以便在使用不同运行时的两个.dll之间进行通信。很明显,如果你有一些std::vector<__int64>和两个dll - 一个vs2010,一个vs2015--他们不会相互礼貌地工作。然后我就想到了 - 为什么我不能在一侧以ipc方式结构序列化并在另一侧反序列化 - 然后vs run-times将相互平滑地工作。

长话短说 - 我已经创建了单独的接口,用于发送下一个数据块和请求下一个数据块。两者都在解码时工作 - 这意味着如果你有10个条目的向量,每个字符串1 Mb,共享内存是10 Kb - 那么传输整个数据需要1 * 10 * 1024/10次。每个下一个请求后跟多个未完成的函数调用 - 可以通过SendChunk或GetNextChunk取决于传输方向。

现在 - 我希望编码和解码同时发生但没有任何线程 - 然后我想出了使用setjmp和longjmp的解决方案。我附上下面的部分代码,只是为了让您了解整个机器中发生的事情。

#include "..."
#include <setjmp.h>                     //setjmp

class Jumper: public IMessageSerializer
{
public:
    char lbuf[ sizeof(IpcCommand) + 10 ];
    jmp_buf     jbuf1;
    jmp_buf     jbuf2;
    bool        bChunkSupplied;

    Jumper() :
        bChunkSupplied(false)
    {
        memset( lbuf, 0 , sizeof(lbuf) );
    }

    virtual bool GetNextChunk( bool bSend, int offset )
    {
        if( !bChunkSupplied )
        {
            bChunkSupplied = true;
            return true;
        }

        int r = setjmp(jbuf1);
        ((_JUMP_BUFFER *)&jbuf1)->Frame = 0;

        if( r == 0 )
            longjmp(jbuf2, 1);

        bChunkSupplied = true;
        return true;
    }

    virtual bool SendChunk( bool bLast )
    {
        bChunkSupplied = false;
        int r = setjmp(jbuf2);
        ((_JUMP_BUFFER *)&jbuf2)->Frame = 0;
        if( r == 0 )
            longjmp(jbuf1, 1);

        return true;
    }

    bool FlushReply( bool bLast )
    {
        return true;
    }

    IpcCommand* getCmd( void )
    {
        return (IpcCommand*) lbuf;
    }

    int bufSize( void )
    {
        return 10;
    }
}; //class Jumper

Jumper jumper;

void main(void)
{
    EncDecCtx enc(&jumper, true, true);
    EncDecCtx dec(&jumper, false, false);
    CString s;

    if( setjmp(jumper.jbuf1) == 0 )
    {
        alloca(16*1024);
        enc.encodeString(L"My testing my very very long string.");
        enc.FlushBuffer(true);
    } else {
        dec.decodeString(s);
    }

    wprintf(L"%s\r\n", s.GetBuffer() );
}

这里有几个问题。在第一次调用setjmp后,我使用alloca() - 从堆栈中分配内存,它将在返回时自动同步。 alloca只能在第一次跳转时发生,因为任何函数调用总是使用callstack(以保存返回地址)并且它可以破坏第二个&#34; thread&#34;调用堆栈。

有很多文章讨论了setjmp和longjmp的危险程度,但现在这已经成为一种有效的解决方案了。堆栈大小(16 Kb)是下一个函数调用的预留 - decodeString等等 - 如果不够,它可以调整到更大。

尝试完这段代码后,我发现x86代码工作正常,但是64但是没有用 - 我遇到的问题与此处描述的类似:

An invalid or unaligned stack was encountered during an unwind operation

类似文章建议我添加了((_JUMP_BUFFER *)&jbuf1)->Frame = 0;种重置 - 之后64位代码开始工作。目前库没有使用任何异常机制,我不打算使用任何机制(如果需要在编码*解码*函数调用中,将尝试捕获所有内容。

所以问题:

  • 在代码中禁用展开是否可以接受? (((_JUMP_BUFFER *)&jbuf1)->Frame = 0;)在上下文setjmp / longjmp中,unwinding的含义是什么?

  • 您是否发现给定代码snipet存在任何潜在问题?

0 个答案:

没有答案