linux多线程 & IPC【12】System V 共享内存

    System V的IPC包括System V消息队列,System V信号量和System共享内存。特征是使用key_t来标志,一般是一个32位的整数,正式说法是一个不小于32位的整数。

    没有亲缘关系的进程之间需要约定好一个文件或目录名(反正目录也是文件),以及一个整数值,然后调用ftok()函数返回一个key_t。

    key_t类型在<sys/types.h>中定义。

    函数ftok原型为:

#include <sys/ipc.h>
/* Generates key for System V style IPC.  */
key_t ftok (const char *pathname, int proj_id);
    得到key_t类型的IPC键后,就可以调用shmget函数获得共享内存标志符了。这个标志符是一个int,一般进程间通信,总有一个是相当于服务器的,他来创建这个共享内存,其他进程默认假定该共享内存已经存在。

POSIX 共享内存的大小可以用ftruncate随时修改,但System V的共享内存在shmget调用之后就确定了无法修改。

http://blog.csdn.net/zhangzhenghe/article/details/6838019

1.创建

(1)在服务器端,需要进行创建:

key_t kt = ftok("/home/administrator", 0);

int id = shmget(kt, 1024, IPC_CREAT | 0666);

关键的地方:1024为字节数,IPC_CREAT表示不存在则创建,存在则直接用;IPC_CREAT|IPC_EXCL表示不存在则创建,存在则返回-1退出;0666表示权限,注意前面的0,表示八进制,切记!

(2)在客户端,需要创建:

key_t kt = ftok("/home/administrator", 0);

int id = shmget(kt, 0,0666);

由于共享内存区已经存在,所以第二个参数必须为0,第三个参数也跟creat不相干,指定权限位即可。

2.绑定

key_t kt = ftok("/home/administrator", 0);

int id = shmget(kt, 0,0666);

p = shmat( id, NULL ,0);

p是一个指针,什么指针都行。

然后就可以进行读写了。

3.解除绑定

key_t kt = ftok("/home/administrator", 0);

int id = shmget(kt, 0,0666);

char *p=shmat(id,NULL,0);

shmdt(p);

4.删除

key_t kt = ftok("/home/administrator", 0);

int id = shmget(kt, 0,0666);

shmctl(id,IPC_RMID,NULL);

5.获得大小

key_t kt = ftok("/home/administrator", 0);

int id = shmget(kt, 0,0666);

struct shmid_ds buff;

shmctl(id,IPC_STAT,&buff);

printf("ize: %d\n", buff.shm_segsz);


System V 共享内存实现之前的系统日志:

包括4个文件:

mylog.h  sys_v_cle.c  sys_v_ser.c  mylog.c

头文件:

#ifndef _MYLOG_H_
#define _MYLOG_H_

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <sys/shm.h>

#define N_MSG 4			// message的个数
#define LEN_MSG 256		// 每个message的长度
//#define FILE_MODE S_IRUSR | S_IWUSR         //rwxrwxrwx
#define FILE_MODE 00600		//rwxrwxrwx
#define px_ipc_name(x) (x)	//空的宏定义,暂时没有用

struct msg_ctl_str {
    sem_t mutex;
    sem_t empty;
    sem_t full;
    int nput;			// 下一个可以由生产者放置log信息的index序号
    int nread;			// 已经处理完毕的消息序号,初始为-1,这样,下一个要处理的就是0
    char msgdata[N_MSG][LEN_MSG];
} msg_ctl_str;

void my_syslog (const char *msg, char *argv[]);	//给客户端的函数

#endif

sys_v_ser.c。服务器采用独占方式,如果已经存在,则将ftok的第二个参数+1,再次尝试。

 #include "mylog.h"
 
 int main(int argc, char *argv[])
 {
   
    key_t kt;
    int id;
    int n=0;
    struct msg_ctl_str *p;
    int i;
    
     // 创建共享内存区
    kt = ftok(argv[1], atoi(argv[2])+n );
    id = shmget(kt, sizeof(struct msg_ctl_str), IPC_CREAT | IPC_EXCL|0666);
    while (id == -1)
    {
        ++n;
        kt =ftok(argv[1], atoi(argv[2])+n );
        id = shmget(kt, sizeof(struct msg_ctl_str), IPC_CREAT | IPC_EXCL|0666);
    }
    printf("server start! key_t: %s, %d\n", argv[1], atoi(argv[2])+n );
    
    // 映射
    p = shmat( id, NULL ,0);
    if (p==-1)
    {
        printf("shmat fail!\n");
        exit(2);
    }
    
    // 初始化
    sem_init(&(p->mutex),1,1);
    sem_init(&(p->empty),1,N_MSG);
    sem_init(&(p->full),1,0);
    p->nput=0;
    p->nread=-1;
    for(i=0;i<N_MSG;i++)
        p->msgdata[i][0]='\0';

    while(1)
    {
        sem_wait(& (p->full));
        sem_wait(& (p->mutex));
        
        p->nread++;
        p->nread %= N_MSG;
        printf("处理第 %d 条: %s\n", p->nread, p->msgdata[p->nread]);
        
        sem_post(& (p->mutex));
        sem_post(& (p->empty));
    }
    
    // 不会运行
    shmdt(p); // 断开
    shmctl(id, IPC_RMID, NULL); //
    
 }
 

sys_v_cle.c:

 #include "mylog.h"
 
 int main(int argc, char *argv[])
 {
    char *s="I am client";
    my_syslog(s, argv);
    return 0;   
}
    
sys_v_cle.c调用了mylog.c中的函数。mylog.c:

#include "mylog.h"

void
my_syslog (const char *msg, char *argv[])
{
    key_t kt;
    int n=0;
    int id;
    struct msg_ctl_str *p;
   // printf("%s %s\n", argv[1], argv[2]);
    //打开
    kt = ftok( argv[1], atoi(argv[2]+n) );
    id = shmget(kt,0,0666);
    while (id == -1)
    {
        ++n;
        kt = ftok( argv[1], atoi(argv[2]+n) );
        id=shmget(kt,0,0666);
    }
    printf("client key_t: %s, %d--", argv[1], atoi(argv[2])+n );
    
    //映射
    p = (struct msg_ctl_str *)shmat(id,NULL,0);
    if (p==-1)
    {
        printf("shmat fail!\n");
        exit(2);
    }
    
    //干正事
    sem_wait (&(p->empty));	//等待有消息的到来,没有消息的话一直阻塞在这里
    sem_wait (&(p->mutex));	//取得互斥

    // 处理!就是打印到标准输出而已
    strncpy (p->msgdata[p->nput], msg, 255);
    printf ("process %d add a msg to log (%d, %s)\n", getpid (), p->nput,
	    p->msgdata[p->nput]);
    p->msgdata[p->nput][255] = '\0';
    p->nput++;
    p->nput = p->nput % N_MSG;
    //

    sem_post (&(p->mutex));
    sem_post (&(p->full));	//empty的位置增加了一个 
}

开启两个终端,第一个终端启动服务器:

administrator@ubuntu:~/test/sys_v$ ./ss /home/administrator 2 &     <--启动
[4] 5936
administrator@ubuntu:~/test/sys_v$ server start! key_t: /home/administrator, 4     <--打出来的信息。客户端的参数应使用4

administrator@ubuntu:~/test/sys_v$ jobs
[3]-  运行中               ./log_server &  (工作目录:~/test/log_test)
[4]+  运行中               ./ss /home/administrator 2 &


第二个终端启动客户端:

administrator@ubuntu:~/test/sys_v$ ./cc /home/administrator 4
client key_t: /home/administrator, 4--process 5937 add a msg to log (0, I am client)
administrator@ubuntu:~/test/sys_v$ ./cc /home/administrator 4
client key_t: /home/administrator, 4--process 5938 add a msg to log (1, I am client)
administrator@ubuntu:~/test/sys_v$ ./cc /home/administrator 4
client key_t: /home/administrator, 4--process 5939 add a msg to log (2, I am client)
administrator@ubuntu:~/test/sys_v$ ./cc /home/administrator 4
client key_t: /home/administrator, 4--process 5940 add a msg to log (3, I am client)
administrator@ubuntu:~/test/sys_v$ ./cc /home/administrator 4
client key_t: /home/administrator, 4--process 5941 add a msg to log (0, I am client)
administrator@ubuntu:~/test/sys_v$ ./cc /home/administrator 4
client key_t: /home/administrator, 4--process 5942 add a msg to log (1, I am client)
administrator@ubuntu:~/test/sys_v$ ./cc /home/administrator 4
client key_t: /home/administrator, 4--process 5943 add a msg to log (2, I am client)
administrator@ubuntu:~/test/sys_v$ 
客户端一共运行了7次,写了7条消息。第一个终端中的服务器收到消息,就进行处理,把消息相关的信息打出来:

administrator@ubuntu:~/test/sys_v$ 处理第 0 条: I am client                     
处理第 1 条: I am client
处理第 2 条: I am client
处理第 3 条: I am client
处理第 0 条: I am client
处理第 1 条: I am client
处理第 2 条: I am client
共7条。此后服务器再次进行等待。







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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值