嵌入式第二十五天


复习: 
进程间通信方式:信号、管道、共享内存、消息队列、信号量、socket套接字 

信号: 
种类:   kill -l   (man 7 signal)
SIGINT  
SIGQUIT 
SIGALRM 
SIGTSTP
信号的处理方式: 捕捉、忽略 、默认  
函数: signal  kill(pid,SIGINT);  raise  alarm    

管道: 
无名管道: pipe int pfd[2];  pfd[0]读端   pfd[1]写端 
有名管道: mkfifo("pathname",0664);   

新知识:    
共享内存 --- 进程间通信最快

为了在多个进程间交换信息,内核专门留出一块内存区。这段内存可以由需要访问的进程
将其映射到自己的私有地址空间,因此进程就可以直接读写这一段内存区,而不需要数据的复制。
从而大大提高了效率。 

一、 步骤
1. 创建共享内存对象  shmget 
2. 映射          shmat
3. 读写             
4. 解除映射      shmdt
5. 删除共享内存对象  shmctl 


二、 函数
1. 创建共享内存对象  shmget 
函数原型:  int shmget(key_t key, size_t size, int shmflg);
头文件:    #include <sys/ipc.h>
            #include <sys/shm.h>
参数:    参数一: key :IPC_PRIVATE
                         共享内存的键值。 
          参数二: size : 共享内存大小 
          参数三: open() 函数的权限位。 O_RDONLY  O_WRONLY  O_RDWR   O_CREAT  权限位也可以用8进制表示: 0664
*返回值: 成功: 共享内存段标识符  shmid  
         失败: -1 

示例:  shmget(IPC_PRIVATE,128,O_CREAT|O_WRONLY);
        shmget(key,256,O_RDONLY);


函数2:  ftok();  
函数原型:  key_t ftok(const char *pathname, int proj_id);
头文件:      #include <sys/types.h>
             #include <sys/ipc.h>
参数:  参数1: pathname  路径。 要求此路径必须是存在的。 
        参数2: proj_id   1 ~ 255 之间的整数即可。 
*返回值:  是一个键值。可以提供给消息队列或者共享内存使用。 
        
示例: 
        
#include  <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
    key_t key = ftok("/mnt",'a');         
    int shmid = shmget(key,128,O_CREAT|O_WRONLY);
    if(shmid < 0)
    {
        perror("shmget");
        exit(-1);
    }
    printf("OK\n");
    return 0;
}        
    

2. 映射          shmat
函数原型:      void *shmat(int shmid, const void *shmaddr, int shmflg);
头文件:        #include <sys/types.h>
                #include <sys/shm.h>
参数:       参数1:  shmget 的返回值。 
             参数2; shmaddr 将共享内存映射到指定地址。 (通常写 NULL)
             参数3: SHM_RDONLY   共享内存只读。 
                       0      共享内存可读写  
*返回值:  成功: 被映射的段地址 
           失败: -1   
3. 读写             

示例: 
write.c 
///
#include  "my.h"
int main()
{
    key_t key = ftok("/home",66);         
//    printf("key : %d\n",key);
    int shmid = shmget(key,256,IPC_CREAT|0664);  //当参数1为key时,权限使用的是: IPC_CREAT,不是O_CREAT 
    if(shmid < 0)
    {
        perror("shmget");
        exit(-1);
    }
    int *p = shmat(shmid,NULL,0);
    *p = 999;
    return 0;
}

read.c 
/
#include "my.h"
int main()
{
    key_t key = ftok("/home",66);         
    int shmid = shmget(key,256,0);
    if(shmid < 0)
    {
        perror("shmget");
        exit(-1);
    }
    int *p = shmat(shmid,NULL,0);
    printf("%d\n",*p);

    return 0;
}

//练习:进程a键盘获取字符串发给进程b 进程b收到后转为大写并输出    
write.c 
//
#include "my.h"
int main()
{
    key_t key = ftok("/home",'r');         
    int shmid = shmget(key,256,IPC_CREAT|0777);
    if(shmid < 0)
    {
        perror("shmget");
        exit(-1);
    }
    char *p = shmat(shmid,NULL,0);
    gets(p);
    return 0;
}

read.c 
///
#include "my.h"
void change(char *p)
{
    int i;
    for(i=0; p[i]!='\0'; i++)
    {
        if(p[i]>='a'&& p[i]<='z')
        {
            p[i] -= 32;
        }
    }
    return;
}
int main()
{
    key_t key = ftok("/home",'r');         
    int shmid = shmget(key,256,0);
    if(shmid < 0)
    {
        perror("shmget");
        exit(-1);
    }
    char *p = shmat(shmid,NULL,0);
    change(p);
    printf("%s\n",p);
    return 0;
}

/ 查看共享内存信息: ipcs  -m  
/ 删除共享内存信息: ipcrm -m  shmid 


4. 解除映射      shmdt
函数原型:  int shmdt(const void *shmaddr);
头文件:   同 shmat 
参数:     shmat 的返回值。 
返回值:    成功: 0 
            失败: -1  

5. 删除共享内存对象  shmctl 
函数原型:        int shmctl(int shmid, int cmd, struct shmid_ds *buf);
头文件:     #include <sys/ipc.h>
             #include <sys/shm.h>
参数:  参数1: shmget  的返回值。  
        参数2: IPC_STAT     获取共享内存状态信息
                IPC_SET      设置共享内存信息
                IPC_RMID     删除共享内存 
        参数3: struct shmid_ds * 
          struct shmid_ds {
               struct ipc_perm shm_perm;    /* Ownership and permissions */
               size_t          shm_segsz;   /* Size of segment (bytes) */
               time_t          shm_atime;   /* Last attach time */
               time_t          shm_dtime;   /* Last detach time */
               time_t          shm_ctime;   /* Last change time */
               pid_t           shm_cpid;    /* PID of creator */
               pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
               shmatt_t        shm_nattch;  /* No. of current attaches */
               ...
           };
           
//练习1. 一个进程将数据写入共享内存后 用信号通知另一个进程 
    另一个进程捕捉信号后 将信息打印
    
create.c 
///    
#include"../my.h"
int main()
{
    key_t key = ftok("/home",'w');
    if(key<0)
    {
        perror("ftok");
        exit(-1);
    }

    int shmid = shmget(key,256,IPC_CREAT|0777);
    if(shmid<0)
    {
        perror("shmget");
        exit(-1);
    }
    return 0;
}
    
write.c 

#include"../my.h"
int main(int argc,char*argv[])
{
    if(argc!=2)
    {
        printf("%s pid\n",argv[0]);
        exit(-1);
    }
    key_t key = ftok("/home",'w');
    if(key<0)
    {
        perror("ftok");
        exit(-1);
    }

    int shmid = shmget(key,0,0);
    if(shmid<0)
    {
        perror("shmget");
        exit(-1);
    }
    char *p = shmat(shmid,NULL,0);
    if(p==(void*)-1)
    {
        perror("shmat");
        exit(-1);
    }

    pid_t pid = atoi(argv[1]);
    while(1)
    {
        puts("please input a string:");
        gets(p);
        kill(pid,SIGINT);
    }
    return 0;
}

read.c 
/    
#include"my.h"
char *p;
void deal_fun(int sig)
{
    printf("%s\n",p);
}
int main()
{
    printf("%d\n",getpid());
    signal(SIGINT,deal_fun);
    key_t key = ftok("/home",'f');
    if(key<0)
    {
        perror("ftok");
        exit(-1);
    }
    int shmid = shmget(key,0,0);
    if(shmid<0)
    {
        perror("shmget");
        exit(-1);
    }
    p = shmat(shmid,NULL,SHM_RDONLY);
    if(p==(void*)-1)
    {
        perror("shmat");
        exit(-1);
    }
    while(1)
    {
        ;
    }
    return 0;
}
//
执行过程:  
gcc create.c -o create  
gcc write.c -o write 
gcc read.c -o read 
./create  
./r     (打印自己进程号)
./w  pid   (向进程号为 pid 的进程发送信号)


附: my.h  
//
#ifndef _MY 
#define _MY  1 

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>

#endif


三、函数(第二组)
1. 函数:  ftruncate
函数原型: int ftruncate(int fd, off_t length);
头文件:   #include <unistd.h>
           #include <sys/types.h>
功能:将参数fd 指定的文件大小,改为length指定的大小
参数:  fd 文件描述符。 
        length : 用这个参数,规定了fd 的大小。 

2. mmap
函数原型:  void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
头文件:   #include <sys/mman.h>
功能: mmap将文件映射到调用进程的地址空间当中。当用mmap映射文件到进程后,
       就可以直接操作这段地址空间进行文件读写操作。
参数: 
参数1: 映射位置。 (一般写NULL, 系统会给分配地址)       
参数2: 空间的大小。 
参数3:PROT_EXEC  Pages may be executed.
       PROT_READ  Pages may be read.
       PROT_WRITE Pages may be written.
       PROT_NONE  Pages may not be accessed.
参数4: 
        MAP_SHARED   共享 
        MAP_PRIVATE  私有
参数5:指定要被映射的文件的描述符。
参数6:要映射的存储区,对应文件的起始偏移量。

返回值: 成功:实际的共享内存地址。 
         失败:MAP_FAILED  ( that is (void *)-1 )

使用示例:  mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);


3.  int munmap(void *addr, size_t length);
功能:  解除映射。 
参数:   参数一 :  mmap  的返回值。 
         参数二 : length  共享内存大小。  
返回值: 成功: 0 
         失败: -1 

示例: 
write.c 

1)打开文件 
2)设置文件大小 
3)映射
4)输入信息到共享内存/输出
5)解除映射 
6)关闭文件描述符 

read.c  
 
步骤同上。 

write.c 
//
#include "../my.h"
#include <sys/mman.h>

int main()
{
    int fd = open("file",O_CREAT|O_EXCL|O_RDWR,0777);
    if(fd < 0)
    {    
        perror("open");
        exit(-1);
    }
    ftruncate(fd,1024);
    int *p = mmap(NULL,1024,PROT_WRITE,MAP_SHARED,fd,0);
    if(p == MAP_FAILED)
    {
        perror("mmap");
        exit(-1);
    }
    *p = 12345;

    munmap(p,1024);
    close(fd);
    return 0;
}

read.c 
///
#include "../my.h"
#include <sys/mman.h>
int main()
{
    int fd = open("file",O_RDWR);
    if(fd < 0)
    {    
        perror("open");
        exit(-1);
    }
    ftruncate(fd,1024);
    int *p = (int *)mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    
    printf("%d\n",*p);
    munmap(p,1024);
    close(fd);
    return 0;
}

//练习:进程1从键盘获取一个字符串 传递给进程2  进程2收到串后 转为大写 在输出到屏幕
write.c 
/
#include "../my.h"
#include <sys/mman.h>

int main()
{
    int fd = open("file",O_CREAT|O_EXCL|O_RDWR,0777);
    if(fd < 0)
    {    
        perror("open");
        exit(-1);
    }
    ftruncate(fd,1024);
    char *p = mmap(NULL,1024,PROT_WRITE,MAP_SHARED,fd,0);
    if(p == MAP_FAILED)
    {
        perror("mmap");
        exit(-1);
    }
    puts("Input a string:");
    gets(p);

    munmap(p,1024);
    close(fd);
    return 0;
}

read.c 
//
#include "../my.h"
#include <sys/mman.h>
void change(char *p)
{
    int i;
    for(i=0; p[i]!='\0'; i++)
    {
        if(p[i]>='a'&& p[i]<='z')
        {
            p[i] -= 32;
        }
    }
    return;
}
int main()
{
    int fd = open("file",O_RDWR);
    if(fd < 0)
    {    
        perror("open");
        exit(-1);
    }
    ftruncate(fd,1024);
    char *p = (char *)mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    change(p);    
    printf("%s\n",p);

    munmap(p,1024);
    close(fd);
    return 0;
}

//作业答案: 有名管道版本的 cat 功能: 

create.c 

#include "my.h"
int main(int argc,char *argv[])
{
    if(argc != 2)
    {
        printf("%s pipe_name\n",argv[0]);
    }
    int ret = mkfifo(argv[1],0644);
    if(ret < 0)
    {
        perror("mkfifo");
        exit(-1);
    }
    return 0;
}

write.c 
/// 
#include "my.h"
int main(int argc,char *argv[])
{
    if(argc != 3)
    {
        printf("%s pipe_name src_name:\n",argv[0]);
        exit(-1);
    }
    int fd = open(argv[1],O_WRONLY);
    int file_fd = open(argv[2],O_RDONLY);
    if(fd < 0||file_fd < 0)
    {
        perror("open");
        exit(-1);
    }

    char buf[50] = "\0";
    while(1)
    {
        bzero(buf,sizeof(buf)) ;
        int ret = read(file_fd,buf,sizeof(buf));
        if(ret == 0)
        {
            break;
        }
        write(fd,buf,sizeof(buf));
    }
    close(file_fd);
    close(fd);
    return 0;
}
 
read.c 
/
#include "my.h"
int main(int argc,char *argv[])
{
    if(argc != 2)
    {
        printf("%s pipe_name:\n",argv[0]);
        exit(0);
    }
    int fd = open(argv[1],O_RDONLY);
    if(fd < 0)
    {
        perror("open");
        exit(-1);
    }
    char buf[50] = "\0";
    while(1)
    {
        bzero(buf,sizeof(buf));
        int ret = read(fd,buf,sizeof(buf));
        if(ret == 0)
        {
            break;
        }
        puts(buf);
    }    
    close(fd);
    unlink(argv[1]);
    return 0;
}


复习本周内容:
 
标准IO : 
FILE *fp = fopen("file.c",'w+');
fclose(fp);
perror();          %s -- strerror(errno);
c = fgetc(fp);                fputc(c,fp);
fgets(buf,n,fp);           fputs(buf,fp);
fread(buf,4,100,fp);       fwrite(buf,4,100,fp);
fseek(fp,-1,SEEK_SET);     num = ftell(fp);
fprintf(fp,"%d,%d\n",a,b);     fscanf(fp,"%d%s",&a,s);
fnprintf(fp,50,"%d,%d\n",a,b);

文件IO : 
int fd = open("/home/linux/a.c",O_CREAT|O_EXCL|O_RDWR|O_TRUNC,0664); 
close(fd);
read(fd,buf,100);
write(fd,buf,100);
lseek(fd,0,SEEK_SET);
bzero(buf,100); 
menset(buf,'a',100);  //一个字节一个字节 操作。 

目录文件: 
DIR *dirp = opendir("/home/linux");
closedir(dirp);
struct dirent *p = readdir(dirp);
                    struct dirent {    
                        d_ino;
                        d_time;
                        ...
                        d_name[256];
                    };
                    printf("%s\n",p->d_name);    
stat("/home/linux",&a);
                    struct stat {
                        st_ino;
                        st_mode;
                        st_nlink;
                        ...
                    };
a.st_mode   -->  S_ISREG()  S_ISDIR()

进程线程: 
day1:  进程、守护进程   
ps -ef    

getpid();  
getppid();
fork();
            if(id == 0)
            {
                child ;
            }
            else if(id > 0)
            {
                father ;
            }
exit(0);    
_exit(0);
wait(NULL);   wait(&a);  // a 是输出型参数:函数执行完,变量a 获取一个值。 
waitpid(pid,&a,0);    // 0 阻塞状态      WNOHANG 非阻塞
execl("/bin/ls","ls","-l",NULL);
execv("/bin/ls",cmd);    char *cmd[] = {"ls","-l",NULL};
execvp("ls",cmd);    char *cmd[] = {"ls","-l",NULL};

守护进程: 
1. fork();   if(id > 0) exit(0);
2. setsid();
3. chdir("/tmp");
4. umask(0);
5. close(0); close(1); close(2);

进程间通信方式: 信号、管道、共享内存、消息队列、信号量、socket套接字
day2: 信号、管道  
man 7 signal   
signal(SIGINT,fun);
signal(SIGALRM,SIG_IGN);
signal(SIGTSTP,SIG_DFL);
kill(pid, SIGALRM);
raise(SIGALRM);
alarm(45);

管道: 
无名管道: 
单工、亲缘关系的进程间、不是文件
先创建管道、后创建进程。 
pipe(int pfd[2]);     pfd[0]  读。 pfd[1]  写。   

有名管道:
是文件。任意进程间通信。 
mkfifo("./fifo",0664);


day3: 共享内存
key = ftok("/home",88);
shmid = shmget(key,128,IPC_CREAT|O_RDWR|0777);
void *p = shmat(shmid,NULL,0);  // NULL 系统会自动分配地址。 0 : 可读写(权限)
p;
shmdt(p);
shmctl(shmid,IPC_RMID,NULL); 
 
 
 
 

//作业:创建子进程代表售票员 父进程代表司机 
售票员捕捉信号SIGINT(代表开车) 发SIGUSR1给司机 司机打印"ready-go!"
售票员捕捉SIGQUIT(代表停车) 发SIGUSR2给司机     司机打印 "stop..."
售票员捕捉SIGTSTP(代表车到总站)发SIGUSR1给售票员 售票员打印 get off!

//作业:实现shell组合   ls|grep w
提示:用pipe实现
1 fork 
2 dup2(pfd[1],1) //所有输出到屏幕的数据都会输出到管道pfd[1]
3 execlp("ls","ls",NULL)
4 dup2(pfd[0],0);//从标准输入里读 改成从管道中读
5 execlp("grep","grep","w",NULL);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值