欢迎光临
我们一直在努力

Next 4 signal、内存共享

atoi 函数概述

atoi(ASCII to Integer)是C/C++标准库中的一个函数,用于将字符串转换为整型数值。定义在头文件 <stdlib.h>(C)或 <cstdlib>(C++)中。

int atoi(const char *str);

作业:

聊天
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>

void* th1(void* arg)
{
int fd = *(int*)arg;
while(1)
{
char buf[100]={0};
read(fd,buf,sizeof(buf));// #quit\\n
if(0== strcmp(buf,"#quit\\n"))
{
//break;
exit(0);
}
printf("from B:%s",buf);
fflush(stdout);
}
return NULL;
}

void* th2(void* arg)
{
int fd = *(int*)arg;
while(1)
{
char buf[100]={0};
printf("to B:");
fgets(buf,sizeof(buf),stdin); // #quit\\n
write(fd,buf,strlen(buf));
if(0 == strcmp(buf,"#quit\\n"))
{
exit(0);
}

}
return NULL;
}

int main(int argc, char **argv)
{
int ret = mkfifo("myfifo1", 0666);
if (-1 == ret)
{
if (EEXIST == errno) // 管道已经存在的错误
{
//
}
else
{
perror("mkfifo");
return 1;
}
}
ret = mkfifo("myfifo2", 0666);
if (-1 == ret)
{
if (EEXIST == errno) // 管道已经存在的错误
{
//
}
else
{
perror("mkfifo");
return 1;
}
}
// open 会阻塞
int fd_w = open("myfifo1", O_WRONLY);
if (-1 == fd_w)
{
perror("open myfifo1");
return 1;
}

// open 会阻塞
int fd_r = open("myfifo2", O_RDONLY);
if (-1 == fd_r)
{
perror("open myfifo2");
return 1;
}

pthread_t tid1,tid2;
pthread_create(&tid1,NULL,th1,&fd_r);
pthread_create(&tid2,NULL,th2,&fd_w);

pthread_join(tid1,NULL);
pthread_join(tid2,NULL);

return 0;
}

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#define MAX 19661
int main(int argc, char** argv)
{
int fd[2] = {0};
// 创建匿名管道,打开管道文件
int ret = pipe(fd);
if (-1 == ret)
{
perror("pipe");
return 1;
}
pid_t pid = fork();
if (pid > 0)
{
// 父进程,关闭读段
close(fd[0]);
int fd_dict = open("/home/linux/dict.txt", O_RDONLY);
if (-1 == fd_dict)
{
perror("open dict");
return 1;
}
while (1)
{
while (1)
{
char buf[4096] = {0};
int rd_ret = read(fd_dict, buf, sizeof(buf));
if (rd_ret == 0)
{
break;
}
write(fd[1], buf, rd_ret); // 最终的退出条件,管道破裂
}
lseek(fd_dict, 0, SEEK_SET); //回到文件的开头
}
close(fd_dict);
}
else if (0 == pid)
{
// 子进程,关闭写段
close(fd[1]);
FILE* fp = fdopen(fd[0], "r");

while (1)
{
int num = 0;
char line_buf[1024] = {0};
char want_word[50] = {0};
printf("input word:");
fgets(want_word, sizeof(want_word), stdin); // hello\\0
want_word[strlen(want_word) – 1] = '\\0';
if (0 == strcmp(want_word, "#quit"))
{
break;
}
while (1)
{
// read(fd[0],line_buf,sizeof(line_buf));
fgets(line_buf, sizeof(line_buf), fp);
char* word = strtok(line_buf, " ");
char* mean = strtok(NULL, "\\r");
if (0 == strcmp(word, want_word))
{
printf("%s %s\\n", word, mean);
break;
}
num++;
if (num >= MAX)
{
printf("can't find,%s\\n", want_word);
break;
}
}
}
exit(0);
}
else
{
perror("fork");
return 1;
}

return 0;
}

一、信号通信(异步通信)

异步通信:支持处理随机事件的能力。

查信号:kill -l(1-31号给./a.out;Linux操作系统信号 34 – 64)

查手册:man 7 signal

2号SIGINT:Ctrl C

kill             -X        XXXXX

发送进程   信号  接收进程

kill -9 1000

a.out 9 1000

Term:终止,请求进程正常退出

lgn:忽略信号

Core:默认行为是终止进程并生成核心转储文件

Stop:停止进程

Cont:继续,该信号用于恢复被暂停的进程。

发送端

#include <sys/types.h

>#include <signal.h>

int kill(pid_t pid, int sig);

功能:通过该函数可以给pid进程发送信号为sig的系统信号。

参数:pid要接收信号的进程pidsig 当前程序要发送的信号编号《===kill -I

返回值:成功0;失败-1。

int main(int argc, char *argv[])
{
if(argc < 3)
{
return 1;
}
pid_t pid = atoi(argv[1]);
int num = atoi(argv[2]);
int ret = kill(pid,num);
if(-1 == ret)
{
perror("kil");
return 1;
}
return 0;
}

unsigned int alarm(unsigned int seconds); == SIGALAM

功能:定时由系统给当前进程发送信号也称为闹钟函数。

闹钟只有一个,定时只有一次有效,但是必须根据代码逻辑是否执行判断

int pause(void);

功能:进程暂停,不再继续执行,除非收到其他信号(信号是被捕获过)

sighandler_t signal(int signum,sighandler_t handler);

功能:修改进程中,signum对应的处理函数(系统中默认提供的那个)。

参数:signum,需要修改函数的对应的信号数。

           handler,需要替换的函数的函数名。

                 有二个宏表示:SIG_DFL表示默认处理;SIG_IGN表示忽略处理

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int flag = 0 ;
void handle(int num)
{
flag = 1;
}

int main(int argc, char *argv[])
{
signal(SIGALRM,handle);
//设置一个闹钟,5s 后,系统送信号给当前进程
alarm(5);
while(1)
{
if(0 == flag)
{
printf("i'm process…\\n");
}
else
{
printf("i'm sleep…\\n");
}
sleep(1);
}
return 0;
}

}

发信号kill -18 24144
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

void handle(int num)
{

}
int main(int argc, char *argv[])
{
signal(SIGCONT,handle);
int i = 0 ;
while(1)
{
printf("i'm process…,pid :%d\\n",getpid());
sleep(1);
i++;
if(5==i)
{
pause(); //进程暂停
}
}
return 0;
}

SIGUSR1系统给用户,预留的信号,自定义的信号

SIGUSR2

SIGCHLD :父子进程中,当子进程退出后,给父进程发送的信号。用于父进程回收子进程

                     资源。

SIGKILL    9强制关闭以及进程

SIGSTOP   19强制咱体以及进程SIGALAM定时器,定时时间到达,由系统发给对应的进程

SIGINT,2,默认ctr1+C发送给进程的,就是这个信号。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

void handle1(int num)
{
static int i = 0 ;
printf("老爸,叫你…\\n");
i++;
if(3 == i)
{
signal(SIGUSR1,SIG_IGN); // 忽略user1 信号
}

}

void handle2(int num)
{
static int i = 0 ;
printf("老妈,叫你…\\n");
i++;
if(5 == i)
{
signal(SIGUSR2,SIG_DFL); // user2 信号处理 回复默认,默认是关闭
}

}
int main(int argc, char *argv[])
{
signal(SIGUSR1,handle1);
signal(SIGUSR2,handle2);
while(1)
{
printf("i'm playing…,pid:%d\\n",getpid());
sleep(1);
}
return 0;
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

void handle(int num)
{
pid_t ret = wait(NULL);
printf("recycle pid:%d\\n",ret);
}

int main(int argc, char *argv[])
{
// SIGCHLD ,对于父进程而言,默认情况是忽略
// 当子进程结束后,会由系统 给父进程发送 SIGCHLD 这个信号。
signal(SIGCHLD,handle);
pid_t pid = fork();
if(pid>0)
{
while(1)
{
printf("father ,i'm processing…pid:%d\\n",getpid());
sleep(1);
}
}
else if(0 ==pid)
{
int i=3;
while(i–)
{
printf("child ,i'm processing…,pid:%d\\n",getpid());
sleep(1);
}
exit(0);
}
else
{
perror("fork");
return 1;
}
return 0;
}

二、共享内存

共享内存==》效率最高的进程间通信方式

操作流程:key==》申请对象==》映射对象==》读写对象==》撤销映射==》删除对象

1、key值

key_t ftok(const char *pathname,int proj_id);

功能:通过该函数可以将pathname指定的路径用来以proj_id生成唯一的临时键值。

参数:pathname路径+名称===任意文件,只要不会被删除重建即可。

           proj_id整形的数字,一般用ASCII码的单字符表示与参数1的运算。

返回值:成功返回唯一健值失败-1

2、申请对象:shmget()

#include <sys/ipc.h>

#include <sys/shm.h>

ps auxlgrep a.out

share memory get                 IPC_CREAT|0666

int shmget(key_t key, size_t size, int shmflg);

功能:使用唯一键值key向内核提出共享内存使用申请

参数:key唯一键值

          size要申请的共享内存大小

          shmflg 申请的共享内存访问权限,八进制表示

                如果是第一个申请,则用IPC_CREAT

                如果要检测是否存在,用IPC_EXCL

返回值:成功 返回共享内存id,一般用shmid表示;失败-1。

3、映射对象:

shmat()

void *shmat(int shmid,const void *shmaddr, int shmflg);

功能:将指定shmid对应的共享内存映射到本地内存。

参数:shmid要映射的本地内存

           shmaddr本地可用的地址,如果不确定则用NULL,表示由系统自动分配。

shmf1g0,表示读写SHM_RDONLY,只读

返回值:成功返回映射的地址,一般等于shmaddr失败(void*)-1

4、共享内存的读写:

strcpy,字符串

memcpy,二进制数据

共享内存和管道区别

1.共享内存就是一段内存区域,管道底层实现是队列。

2.共享内存可以指定大小。没有写阻塞,写入数据的大小,大于共享内存的大小,就越界了。没读阻塞,如果写段没有写入数据的话,会读到随机数据。

3.数据会一致保留

共享内存

ipcs -a 查询共享内存,信号量集,消息队列

ipcrm  -m删除共享内存

           -s删除信号量集

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(int argc, char **argv)
{
// 1 ,申请key 值
key_t key = ftok("./", '#');
if (-1 == key)
{
perror("ftok");
return 1;
}
printf("key is %d\\n", key);

// 2.申请共享内存
int shmid = shmget(key, 4096, IPC_CREAT | 0666);
if (-1 == shmid)
{
perror("shmget");
return 1;
}

// 3.映射内存 ,映射到用户空间(0~3G) ,可以读写
void *p = shmat(shmid, NULL, !SHM_RDONLY);
if ((void *)-1 == p)
{
perror("shmat");
return 1;
}
// 4.内存写入数据
strcpy(p, "hello world");
// memcpy(p,"hello world",12);

/*// 4.从共享内存读出数据
// strcpy(p, "hello world");
// memcpy(p,"hello world",12);

printf("shm:%s\\n", (char *)p);
// 5.断开映射关系
shmdt(p);
// 6 .删除共享内存
// shmctl(shmid,IPC_RMID,NULL);
*/

//5.断开映射关系
shmdt(p);
return 0;
}

赞(0)
未经允许不得转载:171主机测评 » Next 4 signal、内存共享
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址