zoukankan      html  css  js  c++  java
  • NDK下IPC问题

    由于AllJoyn的join session timeout问题一直无法解决,我们怀疑AllJoyn有些内部变量没有清理干净,因此考虑将AllJoyn相关功能放到一个单独的进程中,一旦join session timeout,就重启该进程。

    这就涉及到IPC问题。

    因为我们写的是通用模块,需要在DTV(arm平台linux)和Android(NDK)上运行,因此就必须考虑各种IPC手段的可用性了。

    一开始我考虑直接使用socket进行IPC(肯定可用),但有人说消息队列、共享内存、管道之类的也可以用。于是俺就mmap+信号量实现了一个简单的IPC类:

    /* 
     * File:   ipc.h
     * Author: raozf
     *
     * Created on 2013年9月17日, 上午11:04
     */
    
    #ifndef IPC_H
    #define    IPC_H
    
    #include <semaphore.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    //semaphore name
    const std::string IPC_SEM = "alljoyn_sem";
    //mmap length
    const size_t IPC_MMAP_LEN = 1 * 1024 * 1024;
    
    /*
     * helper class for IPC  between ****forked**** processes.
     * implemented by semaphore and mmap
     */
    class IPC
    {
    public:
        IPC():_mutex(NULL), _memory(NULL)
        {
            //unnamed semaphore should use sem_init()
            
            //open named semaphore, shared between processes
            _mutex = sem_open(IPC_SEM.c_str(), O_CREAT, O_RDWR, 1);
            if(_mutex == SEM_FAILED || _mutex == NULL)
            {
                LOGV("[ContextSharing]IPC::IPC() sem_open() failed. semaphore name:%s, %s", IPC_SEM.c_str(), strerror(errno));
                return;
            }
            
            /*
             * http://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index1.html
             */
            //create a anonymous mmap
            _memory = (char*)mmap(NULL, IPC_MMAP_LEN, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
            if(_memory == MAP_FAILED || _memory == NULL)
            {
                LOGV("[ContextSharing]IPC::IPC() mmap() failed. %s", strerror(errno));
                deinit();
                return;
            }
        }
    
        ~IPC()
        {
            deinit();
        }
        
        //send msg to other process
        //header+message
        //   int         char*
        void send(const std::string& msg)
        {
            *((int*)_memory) = msg.length();
            memcpy(_memory + sizeof(int), msg.c_str(), msg.length());
            sem_post(_mutex);
        }
        
        //receive from other process
        std::string recv()
        {
            sem_wait(_mutex);//will block
            return std::string(_memory + sizeof(int),  (int)(_memory));
        }
    
    private:
        void deinit()
        {
            if(_mutex != NULL)
            {
                /* destory an unnamed semaphore, initialized by sem_init()
                //sem_destroy(_mutex);
                 */
                
                // closes  the  named semaphore, but still existed in system kernel
                sem_close(_mutex);
                _mutex = NULL;
                
                //remove semaphore from system kernel(if it's reference is 0--which decremented  by sem_close())
                //removes  the  named  semaphore  referred  to  by name.  The semaphore name is removed immediately.  
                //The semaphore is destroyed once all other processes that have the semaphore open close it.
                sem_unlink(IPC_SEM.c_str());
            }
            
            if(_memory != NULL)
            {
                munmap(_memory, IPC_MMAP_LEN);
                _memory = NULL;
            }        
        }
        
    private:
        sem_t* _mutex;
        char* _memory;
    };
    
    #endif    /* IPC_H */

    辅助类,封装一个线程专门等待信号量、接收数据:

    /* 
     * File:   ThreadedIPC.h
     * Author: raozf
     *
     * Created on 2013年9月17日, 下午3:21
     */
    
    #ifndef THREADEDIPC_H
    #define    THREADEDIPC_H
    
    #include "Common/ThreadManager.h"
    #include "delegate.h"
    #include "ipc.h"
    
    static const OID OID_ThreadedIPC = { 0x8f52a31f, 0x51d5, 0x462b, { 0xa9, 0x8d, 0x40, 0x70, 0xa3, 0xf6, 0xb5, 0x7f } };
    class ThreadedIPC
        :public CObjectRoot<CObjectMultiThreadModel>
        ,public IThreadClient
    {
    public:
        PSFRESULT FinalConstruct()
        {
            PSFRESULT res = PSF_E_FAIL;
            
            CHK_PSFRESULT(_listen_thread.Initialize());
            _listen_thread.AddTask(this, NULL);
            
            CLEANUP:
                return res;
        }
        
        void FinalRelease()
        {
            _listen_thread.Terminate();
        }
        
        void Send(const std::string& msg)
        {
            _sharer.send(msg);
        }
        
    private:
        void OnExecute(void* pArg)
        {
            while(true)
            {
                _delegate_recv(_sharer.recv());
            }
        }
        
        void OnTerminate(void* pArg)
        {
        }
    
    public:
        delegate::Delegate<void(std::string)> _delegate_recv;
        
    private:
        CTaskWorker _listen_thread;
        IPC _sharer;
    
        BEGIN_OBJECT_INTERFACE_MAP()
            OBJECT_INTERFACE_ENTRY(OID_ThreadedIPC, this);
        END_OBJECT_INTERFACE_MAP()
    };
    
    #endif    /* THREADEDIPC_H */

    这里面用到了我们自己写的delegate和thread类(先忽略之)。

    但在android上运行时却报错:

    IPC::IPC() sem_open() failed. semaphore name:alljoyn_sem, Function not implemented

    看来信号量在NDK下是用不了的。

    而且,不仅仅信号量,共享内存、消息队列在NDK下都不能用

    参见讨论:https://groups.google.com/forum/#!topic/android-ndk/FzJIsJIxCX4

    http://stackoverflow.com/questions/18603267/cross-process-locking-with-android-ndk

    (但管道可用?http://stackoverflow.com/questions/8471552/porting-c-code-which-uses-fork-to-android

    Android源代码中的文档说明:http://www.netmite.com/android/mydroid/1.6/bionic/libc/docs/SYSV-IPC.TXT

    (该文件在Android4。3中似乎已经移出该文档)

    Android does not support System V IPCs, i.e. the facilities provided by the
    following standard Posix headers:
    
      <sys/sem.h>   /* SysV semaphores */
      <sys/shm.h>   /* SysV shared memory segments */
      <sys/msg.h>   /* SysV message queues */
      <sys/ipc.h>   /* General IPC definitions */
    
    The reason for this is due to the fact that, by design, they lead to global
    kernel resource leakage.

    原因就是防止内核资源泄露。

    更重要的问题在于:fork()也尽量不要用。

    道理很简单:我们不应该控制android的底层,这些api会造成系统的不稳定。

    https://groups.google.com/forum/#!msg/android-platform/80jr-_A-9bU/nkzslcgVrfYJ

    Bear in mind that the Dalvik VM doesn't like fork() much, and goes into
    conniptions if you try to do *any* work between the fork() and the
    exec().

    https://groups.google.com/forum/#!topic/android-ndk/FzJIsJIxCX4

    悲催!

     ----------------------------

    ps:学到了一个命令“ipcs”,查看系统中共享内存、信号量状态:

    $ ipcs

    ------ Shared Memory Segments --------
    key shmid owner perms bytes nattch status

    ------ Semaphore Arrays --------
    key semid owner perms nsems

    ------ Message Queues --------
    key msqid owner perms used-bytes messages

  • 相关阅读:
    希尔伯特空间(Hilbert Space)
    深度神经网络:特点、问题及解决
    深度神经网络:特点、问题及解决
    中英文对照 —— 手机 App/PC 端软件(系统)、互联网
    中英文对照 —— 手机 App/PC 端软件(系统)、互联网
    Opencv决策树分类器应用
    OpenCV实现朴素贝叶斯分类器诊断病情
    机器学习的实现(语言及库的选择)
    机器学习的实现(语言及库的选择)
    《The Economist》的阅读
  • 原文地址:https://www.cnblogs.com/chutianyao/p/3328432.html
Copyright © 2011-2022 走看看