基于信号量的进程间通信
信号量IPC操作考查
编程要求
根据提示,在右侧编辑器补充代码,了解OpenEuler系统如何使用信号量进行IPC通信,代码中先用sem_read_array[]数组存储数据,并进行信号量与数据的输出,我们需要补充代码使用semctl函数输出一样的数据。
#include <errno.h>
#define MAX_SEMAPHORES 5
#include <stdio.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <errno.h>
#include <stdlib.h> //以使用exit函数
#define MAX_SEMAPHORES 5
int main(int argc,char *argv[])
{
int i, ret, semid;
unsigned short sem_array[MAX_SEMAPHORES];
unsigned short sem_read_array[MAX_SEMAPHORES];
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;
semid = semget( IPC_PRIVATE, MAX_SEMAPHORES,IPC_CREAT | 0666 );
if (semid != -1)
{
for ( i = 0 ; i < MAX_SEMAPHORES ; i++ )
{
sem_array[i] = (unsigned short)(i+1);
}
arg.array = sem_array;
ret = semctl( semid, 0, SETALL, arg);
if (ret == -1)
printf("SETALL failed (%d)\n", errno);
arg.array = sem_read_array;
ret = semctl( semid, 0, GETALL, arg );
if (ret == -1)
printf("GETALL failed (%d)\n", errno);
for ( i = 0 ; i < MAX_SEMAPHORES ; i++ )
{
printf("Semaphore %d, value %d\n", i, sem_read_array[i] );
}
for (i = 0; i < MAX_SEMAPHORES; i++) {
union semun getval_arg;
// 注意:getval_arg.val 在这里不需要设置,因为 GETVAL 不使用它
int sem_value = semctl(semid, i, GETVAL, getval_arg);
if (sem_value == -1) {
printf("GETVAL for semaphore %d failed (%d)\n", i, errno);
exit(EXIT_FAILURE);
}
printf("Semaphore %d, value %d\n", i, sem_value);
}
ret = semctl( semid, 0, IPC_RMID );
}
else
printf("Could not allocate semaphore (%d)\n", errno);
return 0;
}
记得引入<stdlib.h>包,以便使用exit函数
基于命名管道与信号的进程间通信
命名管道与信号IPC操作考查
编程思路
根据提示,在右侧编辑器补充代码,使用SIGPIPE信号进行记录,读通道关闭后写通道写入。首先子进程以读的方式打开管道,然后父进程以写的方式打开管道,父进程当即睡眠1秒,子进程关闭读管道,当父进程休眠完成后开始写入,会发出写入失败信号。
#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include<signal.h>
#include<sys/types.h>
void handler(int sig)
{
printf("sig=%d\n",sig);
}
int main(void)
{
int j;
signal(SIGPIPE,handler);//在reader中止之后写Pipe的时候发送
unlink("FIFO");
mkfifo("FIFO",0644);
pid_t pid;
pid=fork();
if(pid==0)
{
/*子进程打开读管道,随后关闭管道*/
int fd;
fd = open("FIFO",O_RDONLY);
close(fd);
}
else
{
/*父进程打开写通道,休眠1秒,尝试写入*/
int fd;
fd = open("FIFO",O_WRONLY);
int ret;
sleep(1);
ret = write(fd,"heoolOpenEuler",14);
}
}
Linux vi/vim编辑器
第1关:vi/vim基本用法
编程要求
本关任务是学会如何启动和退出
vi/vim
编辑器。注意:在执行本关任务前,首先执行如下命令来初始化任务环境
rm -fr /root/oldFile > /dev/null 2>&1
rm -fr /root/.oldFile > /dev/null 2>&1
echo "welcome to Vi/Vim" > /root/oldFile && echo "welcome to Vi/Vim" > /root/.oldFile
具体编程要求如下:
使用vi/vim编辑器查看当前目录下已存在文件oldFile,然后保存退出vi/vim编辑器;
rm -fr /root/oldFile > /dev/null 2>&1
rm -fr /root/.oldFile > /dev/null 2>&1
echo "welcome to Vi/Vim" > /root/oldFile && echo "welcome to Vi/Vim" > /root/.oldFile
vim oldFile
然后再使用:wq退出,测评即可
第2关:vi/vim工作模式切换
编程要求
本关任务是学会如何使用
vi/vim
编辑器进行对文件编辑操作。具体编程要求如下:
使用vi/vim编辑器在当前目录下打开一个新的文件newFile;
然后在文件中写入welcome to vi/vim字符串(注意不用输入换行操作);
保存并退出;
vim newFile
首先进入的是命令模式,然后键盘按“i”进入输插模式,输入:
welcome to vi/vim
键盘按 ESC退出插入模式,最后输入
:wq
保存并退出,测评
vi/vim命令模式
编程要求
本关任务是学会如何使用
vi/vim
编辑器在命令模式下对文件进行操作。注意:在执行本关任务前,首先执行如下命令来初始化任务环境
rm -fr /root/file.txt > /dev/null 2>&1
echo "first" >> /root/file.txt
echo "second" >> /root/file.txt
echo "third" >> /root/file.txt
echo "fourth" >> /root/file.txt
echo "fifth" >> /root/file.txt
具体编程要求如下:
使用vi/vim编辑器打开当前目录下的file.txt文件;
删除当前文件第二行内容;
并将第一行内容复制到文件最后;
保存并退出;
rm -fr /root/file.txt > /dev/null 2>&1
echo "first" >> /root/file.txt
echo "second" >> /root/file.txt
echo "third" >> /root/file.txt
echo "fourth" >> /root/file.txt
echo "fifth" >> /root/file.txt
vim file.txt
然后将光标移到第二行,键盘按下dd,删除第二行
再将光标移回第一行,按下键盘yy复制第一行
最后将光标移到最后一行,点击p粘贴
:wq
测评
vi/vim底线命令模式
编程要求
本关任务是学会在
vi/vim
底线命令模式下,将已打开文件的部分内容另存为一个文件,同时对当前文件中的本分内容进行替换操作。注意:在执行本关任务前,首先执行如下命令来初始化任务环境
rm -fr /root/oldFile.txt > /dev/null 2>&1
echo "first old" >> /root/oldFile.txt
echo "second old" >> /root/oldFile.txt
echo "third old" >> /root/oldFile.txt
echo "fourth old" >> /root/oldFile.txt
echo "fifth old" >> /root/oldFile.txt
具体编程要求如下:
使用vi/vim编辑器打开当前目录下的oldFile.txt文件;
将文件第2-5行内容另存为oldFileCpy.txt文件;
将当前文件的所有old字符串替换为new字符串;
保存并退出;
rm -fr /root/oldFile.txt > /dev/null 2>&1
echo "first old" >> /root/oldFile.txt
echo "second old" >> /root/oldFile.txt
echo "third old" >> /root/oldFile.txt
echo "fourth old" >> /root/oldFile.txt
echo "fifth old" >> /root/oldFile.txt
vim oldFile.txt
进入命令模式后输入
:2,5 w oldFileCpy.txt
回车,此时文件已另存,接下来是字符串替换,输入
:1,$s/old/new/g
回车,最后使用:wq退出,测评
读文件系统函数
read函数是系统调用从文件描述符fd指向的文件中,读取count个字节到buf中; 如果read成功,则返回读到的字节数,如果已达到结尾,则返回0,出错,返回-1 函数原型:
//头文件
#include <unistd.h>
//原型
ssize_t read(int fd, void *buf, size_t count);
参数说明:
fd:文件描述符
buf:保存读入信息的缓存
count:要读取的字节数
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#define rwmode 0
int main()
{
int fd;
char buffer[1024];
int n;
fd = open("/data/workspace/myshixun/case1/testFIle", rwmode);
if (fd < 0)
{
printf("Open file error!\n");
exit(1);
}
else
printf("open testFIle ok!\n");
//请使用read函数将其读入buffer中
n = read(fd, buffer, sizeof(buffer) - 1);
buffer[n] = '\0';
printf("%s\n", buffer);
close(fd);
return 0;
}
写文件系统函数
write函数
write系统调用将buf所指向的缓冲区的count个字节内容写入fd指向的文件; 如果write成功,则返回写入的字节数,出错返回-1 函数原型:
//头文件
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数说明:
fd:要写入的文件
buf:要写入的信息所在的缓存
count:要写入的字节数
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define resource_mode 0
#define destination_mode 0774
#define FILESIZE 1024
int main(int argc, char *argv[])
{
int resource_fd, destination_fd;
char buffer[FILESIZE], *p;
int readbytes, writebytes;
if (argc != 3)
{
printf("Usage:copy from resource file to destination file\n %s src_file dest_file\n", argv[0]);
exit(0);
}
if ((resource_fd = open(argv[1], resource_mode)) == -1)
{
perror("Can't open source file");
exit(0);
}
if ((destination_fd = creat(argv[2], destination_mode)) == -1)
{
perror("Can't create destination file");
exit(0);
}
// 请使用read函数读取前1024字节的内容读到缓冲区buffer中
while ((readbytes = read(resource_fd,buffer,FILESIZE))>0)
{
p = buffer;
if ((readbytes == -1) && (errno != EINTR))
break;
else if (readbytes > 0)
{
// 请使用write函数读取到的前1024字节的内容写到目的文件中
while ((writebytes = write(destination_fd,p,readbytes))>0)
{
if ((writebytes == -1) && (errno != EINTR))
break;
else if (writebytes == readbytes)
break;
else if (writebytes > 0)
{
p += writebytes;
readbytes -= writebytes;
}
}
if (writebytes == -1)
break;
}
}
close(resource_fd);
close(destination_fd);
return 0;
}
进程基础操作
fork知识理解
fork函数后的的代码在子进程中也被执行,实际上其他代码也在子进程中,子进程执行位置为fork返回位置后,之前代码无法执行。
fork 理解步骤
step1、设由shell直接执行程序,生成了进程P。P执行完Part. A的所有代码。
step2、当执行到pid = fork();时,P启动一个进程Q,Q是P的子进程,和P是同一个程序的进程。Q继承P的所有变量、环境变量、程序计数器的当前值。
step3、在P进程中,fork()将Q的PID返回给变量pid,并继续执行Part. B的代码。 step4、在进程Q中,将0赋给pid,并继续执行Part. B的代码。
这里有三个点非常关键:
1、P执行了所有程序,而Q只执行了Part. B,即fork()后面的程序。(这是因为Q继承了P的PC-程序计数器)
2、Q继承了fork()语句执行时当前的环境,而不是程序的初始环境。
3、P中fork()语句启动子进程Q,并将Q的PID返回,而Q中的fork()语句不启动新进程,仅将0返回。
编程要求
根据提示,在右侧编辑器编写代码,通过一行输出代码,使得子进程和父进程的都输出"bey!",之间用空格隔开。
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
/*请开始填写*/
pid_t pid = fork();
if(pid==0){
printf("bye! ");
}
else{
printf("bye! ");
}
return 0;
}