命名信号量跟系统共享内存

共享内存是最快的可用IPC形式:

它允许多个不相关的Process去访问同一部分逻辑内存。

如果需要在两个运行的Process之间传输数据,共享内存跟FIFO(命名管道),文件共享文件相比是效率极高的一种方法。

一旦内存区映射到共享它的Process的地址空间,这些Process间的数据传递就不会再涉及到内核,这样可以减少系统调用时间,提高了效率。


共享内存是IPC为一个进程创建一个特殊的地址范围,它将出现在该Process的地址空间。

其他Process可以通过把同一段内存逻辑上连接到自己的地址空间。

所有的Process都可以访问共享内存的地址。

如果一个Process修改了共享内存的内容, 其他Process马上就可以看到。


共享内存本生没有任何的同步功能,所以对于共享内存的同步控制问题由“程序猿”自行负责。

可选的同步方式可以是互斥锁/条件变量/读写锁/记录锁/信号灯等等。


以下代码用命名信号量同步。

因为命名信号量在linux系统中有独立可见的文件,所以用在两个没有血缘关系的Process之间,二无名信号量在文件系统中并没有实例文件,

所以大多用在线程同步,所以以下代码采用命名信号量。

//=================================================================================================//

memory.h文件

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>
#include <stdlib.h>

#define PRINT( fmt, arg... ) printf( fmt, ##arg )

#define SHARMEM "ShareMemory"
#define SEMNAME "SemLock"

#define MAPLEN ( 2 * 1024 ) //共享内存大小

typedef struct
{
    int    ShmFd;  //共享内存对应的文件描述符,可以考虑下跟常规文件的区别
    char  *ShmPtr;  //共享区地址
    sem_t *SemPtr;  //命名信号量
    
}SharedMemory;

......

//=================================================================================================//

memory.c文件

#include "memory.h"

//====================信号量部分代码===========================//

sem_t *SemOpen( char *SemName, int OpenMode, int CreateMode, int InitVal )
{
    sem_t *SemPtr;
    char Buf[ 40 ] = "/dev/shm/sem.";

    strcat( Buf, SemName );

    //判断信号量文件在系统中是否存在

    if( 0 != access( Buf, F_OK ) )
    {
        SemPtr = sem_open( SemName, OpenMode | O_CREAT, CreateMode, InitVal );
        if( NULL == SemPtr )
        {
            PRINT( "%d  %s\r\n", __LINE__, strerror( errno ) );
            goto SemOpenOut;
        }
    }
    else
    {
        SemPtr = sem_open( SemName, OpenMode );
        if( NULL == SemPtr )
        {
            PRINT( "%d  %s\r\n", __LINE__, strerror( errno ) );
            goto SemOpenOut;
        }
    }
    
SemOpenOut:
    return SemPtr;
}

void SemDelete( char *SemName, sem_t *SemPtr )
{
    char Buf[ 40 ] = "/dev/shm/sem.";

    strcat( Buf, SemName );

    if( NULL != SemPtr )
    {
        sem_close( SemPtr );
    }

    if( 0 == access( Buf, F_OK ) )
    {
        sem_unlink( SemName );
    }
}

//===================共享内存部分代码===================//

int ShmOpen( char *ShmName, int OpenMode, int CreateMode )
{
    int ShmFd = 0;
    char Buf[ 40 ] = "/dev/shm/";

    strcat( Buf, ShmName );

    //判断共享内存文件是否存在
    if( 0 != access( Buf, F_OK ) )
    {
        ShmFd = shm_open( ShmName, OpenMode | O_CREAT, CreateMode );
        if( ShmFd < 0 )
        {
            PRINT( "%d  %s\r\n", __LINE__, strerror( errno ) );
            goto ShmOpenOut;
        }
    }
    else
    {
        ShmFd = shm_open( ShmName, OpenMode, CreateMode );
        if( ShmFd < 0 )
        {
            PRINT( "%d  %s\r\n", __LINE__, strerror( errno ) );
            goto ShmOpenOut;
        }
    }
    
ShmOpenOut:
    return ShmFd;
}

void ShmDelete( char *ShmName, int ShmFd )
{
    char Buf[ 40 ] = "/dev/shm/";

    strcat( Buf, ShmName );
    
    if( ShmFd > 0 )
    {
        close( ShmFd );
    }

    if( 0 == access( Buf, F_OK ) )
    {
        shm_unlink( ShmName );
    }
}

//映射共享内存

char *ShareMemGet( int MapLen, int *MemFd, int offset, int MapFrotect, int MapFlag )
{
    char *MapAddr = NULL;

    //注意该处ftruncate的功能,设置共享内存文件的大小,必须大于等于共享内存的大小

    if( ftruncate( *MemFd, MapLen ) < 0 )
    {
        PRINT( "%d  %s\r\n", __LINE__, strerror( errno ) );
        goto ShareMemGetOut;
    }

    MapAddr = ( char * )mmap( MapAddr, MapLen, MapFrotect, MapFlag, *MemFd, 0 );
    if( NULL == MapAddr )
    {
        PRINT( "%d  %s\r\n", __LINE__, strerror( errno ) );
        goto ShareMemGetOut;
    }

ShareMemGetOut:
    return MapAddr;
}

void ShareMemDelete( char *MapAddr, int MapLen )
{
    if( NULL != MapAddr )
    {
        if( munmap( MapAddr, MapLen ) < 0 )
        {
            PRINT( "%d  %s\r\n", __LINE__, strerror( errno ) );
        }
    }
}

//==================创建共享内存====================//

int SharedMemCreate( SharedMemory **MemPtr )
{
    int ret = 0;

    if( NULL == ( *MemPtr = ( SharedMemory * )malloc( sizeof( SharedMemory ) ) ) )
    {
        PRINT( "%d  %s\r\n", __LINE__, strerror( errno ) );
        ret = -1;
        goto SharedMemCreateOut;
    }
    //获取保护共享内存区域的信号量
    if( NULL == ( ( *MemPtr )->SemPtr = SemOpen( SEMNAME, O_RDWR, 0x1a4, 1 ) ) )
    {
        PRINT( "%d  Sem open failed!\r\n", __LINE__ );
        ret = -1;
        goto SharedMemCreateOut;
    }
    //创建并打开共享内存文件
    if( ( ( *MemPtr )->ShmFd = ShmOpen( SHARMEM, O_RDWR, 0x1a4 ) ) < 0 )
    {
        PRINT( "%d  Shm open failed!\r\n", __LINE__ );
        ret = -1;
        goto SharedMemCreateOut;
    }
    //将共享内存文件映射到当前Process
    if( NULL == ( ( *MemPtr )->ShmPtr = ShareMemGet( MAPLEN, &( ( *MemPtr )->ShmFd ), 0, PROT_READ | PROT_WRITE, MAP_SHARED ) ) )
    {
        PRINT( "%d  Shm open failed!\r\n", __LINE__ );
        ret = -1;
        goto SharedMemCreateOut;
    }

SharedMemCreateOut:
    if( -1 == ret )
    {
        if( NULL != *MemPtr )
        {
            if( NULL != ( *MemPtr )->SemPtr )
            {
                SemDelete( SEMNAME, ( *MemPtr )->SemPtr );
            }

            if( NULL != ( *MemPtr )->ShmPtr )
            {
                ShareMemDelete( ( *MemPtr )->ShmPtr, MAPLEN );
            }

            if( ( *MemPtr )->ShmFd > 0 )
            {
                ShmDelete( SHARMEM, ( *MemPtr )->ShmFd );
            }

            free( *MemPtr );
        }
    }
    
    return ret;
}

void SharedMemDestroy( SharedMemory *MemPtr )
{
    if( NULL != MemPtr )
    {
        if( NULL != MemPtr->SemPtr )
        {
            SemDelete( SEMNAME, MemPtr->SemPtr );
        }
    
        if( NULL != MemPtr->ShmPtr )
        {
            ShareMemDelete( MemPtr->ShmPtr, MAPLEN );
        }
    
        if( MemPtr->ShmFd > 0 )
        {
            ShmDelete( SHARMEM, MemPtr->ShmFd );
        }
    
        free( MemPtr );
    }

}

//=================================================================================================//

Writememory.c文件    //将存标准输入获取的信息写入共享内存区

#include "memory.h"

int main( void )
{
    SharedMemory *MemStPtr = NULL;

    if( SharedMemCreate( &MemStPtr ) < 0 )
    {
        PRINT( "%d  Shared memory create failed!\r\n", __LINE__ );
        goto Out;
    }

    while( 1 )
    {
        sem_wait( MemStPtr->SemPtr );
        PRINT( "memmap firt got the sem!\r\n" );

        if( read( STDIN_FILENO, MemStPtr->ShmPtr, MAPLEN ) < 0 )
        {
            PRINT( "%d  %s\r\n", __LINE__, strerror( errno ) );
        }

        sem_post( MemStPtr->SemPtr );
        PRINT( "memmap firt posted the sem!\r\n" );
        sleep( 1 );
    }
    
Out:
    if( NULL != MemStPtr )
    {
        SharedMemDestroy( MemStPtr );
    }

    return 0;
}
//=================================================================================================//

Readmemory.c文件    //读取并打印共享内存的信息

#include "memory.h"

int main( void )
{
    SharedMemory *MemStPtr = NULL;

    if( SharedMemCreate( &MemStPtr ) < 0 )
    {
        PRINT( "%d  Shared memory create failed!\r\n", __LINE__ );
        goto Out;
    }

    while( 1 )
    {
        sem_wait( MemStPtr->SemPtr );
        PRINT( "memmap second got the sem!\r\n" );

        if( write( STDIN_FILENO, MemStPtr->ShmPtr, strlen( MemStPtr->ShmPtr ) ) < 0 )
        {
            PRINT( "%d  %s\r\n", __LINE__, strerror( errno ) );
        }

        sem_post( MemStPtr->SemPtr );
        PRINT( "memmap second posted the sem!\r\n" );
        sleep( 1 );
    }
    
Out:
    if( NULL != MemStPtr )
    {
        SharedMemDestroy( MemStPtr );
    }

    return 0;

}

//=================================================================================================//


注:信号量跟共享内存的文件并不存在于当前的文件夹下,而是在/dev/shm下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值