Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1620148
  • 博文数量: 441
  • 博客积分: 20087
  • 博客等级: 上将
  • 技术积分: 3562
  • 用 户 组: 普通用户
  • 注册时间: 2006-06-19 15:35
文章分类

全部博文(441)

文章存档

2014年(1)

2012年(1)

2011年(8)

2010年(16)

2009年(15)

2008年(152)

2007年(178)

2006年(70)

分类: LINUX

2007-12-29 16:44:03

利用共享内存(shared memory)可以使我们在任意两个进程间传递数据,而且也是相对简单容易实现的一个方法。在正常情况下,一个进程的所使用的内存区是不允许其它进程访问的。这里我们要开辟的共享内存是例外。
使用共享内存用到的api函数介绍如下:
#include
#include
#include

key_t ftok(const char *pathname, int proj_id);
它有两个参数,一个是字符串,一个是字符。字符串一般用当前进程的程序名,字符一般用来标记这个标识符所标识的共享内存是这个进程所开辟的第几个共享内存。ftok()会返回一个key_t型的值,也就是计算出来的标识符的值。

int     shmget( key_t shmkey , int shmsiz , int flag );
void    *shmat( int shmid , char *shmaddr , int shmflag );
int     shmdt( char *shmaddr );

shmget()是用来开辟/指向一块共享内存的函数。参数定义如下:
key_t shmkey 是这块共享内存的标识符。如果是父子关系的进程间通信的话,这个标识符用IPC_PRIVATE来代替。但是刚才我们的两个进程没有任何关系,所以就用ftok()算出来一个标识符使用了。
int shmsiz 是这块内存的大小.
int flag 是这块内存的模式(mode)以及权限标识
模式可取如下值:          新建:IPC_CREAT
                        使用已开辟的内存:IPC_ALLOC
                        如果标识符以存在,则返回错误值:IPC_EXCL
然后将“模式” 和“权限标识”进行“或”运算,做为第三个参数。
如:    IPC_CREAT | IPC_EXCL | 0666
这个函数成功时返回共享内存的ID,失败时返回-1。


shmat()是用来允许本进程访问一块共享内存的函数。
int shmid是那块共享内存的ID。
char *shmaddr是共享内存的起始地址
int shmflag是本进程对该内存的操作模式。如果是SHM_RDONLY的话,就是只读模式。其它的是读写模式
成功时,这个函数返回共享内存的起始地址。失败时返回-1。

shmdt()与shmat()相反,是用来禁止本进程访问一块共享内存的函数。
参数char *shmaddr是那块共享内存的起始地址。
成功时返回0。失败时返回-1。

此外,还有一个用来控制共享内存的shmctl()函数如下:
#include 
#include 
#include 

int     shmctl( int shmid , int cmd , struct shmid_ds *buf );
int shmid是共享内存的ID。
int cmd是控制命令,可取值如下:
        IPC_STAT        得到共享内存的状态
        IPC_SET         改变共享内存的状态
        IPC_RMID        删除共享内存
struct shmid_ds *buf是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定。
返回值:        成功:0
               失败:-1

注意!!!!!!!!!:在使用共享内存,结束程序退出后。如果你没在程序中用shmctl()删除共享内存的话,一定要在命令行下用ipcrm命令删除这块共享内存。你要是不管的话,它就一直在那儿放着了。

简单解释一下ipcs命令和ipcrm命令。
取得ipc信息:
ipcs [-m|-q|-s]
-m      输出有关共享内存(shared memory)的信息
-q      输出有关信息队列(message queue)的信息
-s      输出有关“遮断器”(semaphore)的信息
%ipcs -m

删除ipc
ipcrm -m|-q|-s shm_id
%ipcrm -m 105

下面用一个简单的例子来说明如何使用共享内存:
程序mcut.c 从标准输入接受字符串,当遇到'q'时退出,然后把输入放入共享内存。
程序mpaste.c 从共享内存取出内容,打印出来。
程序代码如下:
/* mcut.c */
#include
#include
#include
#include

int main()
{
    key_t shmkey;
    int shmid, in_tmp;
    char *head, *pos, in_data[4096], *in_ptr;

    /*生成共享内存标识*/
    shmkey = ftok("mcut", 'a');
    /*获取共享内存id*/
    shmid = shmget(shmkey, sizeof(in_data), IPC_CREAT | 0666);
    /*允许本进程访问共享内存,并获得共享内存首地址*/
    head = pos = shmat(shmid, 0, 0);
    in_ptr = in_data;

    /*从标准输入接收字符,如果是'q'则表示接收完毕*/
    while ( (in_tmp=getchar()) != 'q' )
    {
        *in_ptr = in_tmp;
        in_ptr++;
    }

    *in_ptr = '\0';
    in_ptr = in_data;
   
    /*将标准输入放入共享内存*/
    while ( *in_ptr != '\0' )
    {
        *pos = *in_ptr;
        pos++;
        in_ptr++;
    }
    *pos = '\0';

    /*禁止本进程访问共享内存,即本进程和共享内存脱离关系*/
    shmdt(head);
   
    return 0;
}

/*mpaste.c*/
#include
#include
#include
#include

int main()
{
    key_t shmkey;
    int    shmid;
    char *head, *pos, out_data[4096], *out_ptr;

    /*获取共享内存标识*/
    shmkey = ftok("mcut", 'a');
    /*得到共享内存id*/
    shmid = shmget(shmkey, sizeof(out_data),  0666);
    /*允许本进程访问共享内存,并获取共享内存首地址*/
    head = pos = shmat(shmid, 0, 0);
    out_ptr = out_data;

    /*从共享内存中取出数据*/
    while ( *pos != '\0' )
    {
        *out_ptr = *pos;
        out_ptr++;
        pos++;
    }
    *out_ptr = '\0';
    /*打印从共享内存读出的数据*/
    printf("%s\n", out_data);
    fflush(stdout);

    /*禁止本进程访问共享内存*/
    shmdt(head);
    /*删除共享内存*/
    shmctl(shmid, IPC_RMID, NULL);
   
    return 0;
}

阅读(1775) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~