Linux 编程技术知识要点
非编程题
-
linux中把分区和目录对应的过程叫做
挂载
。 -
信号是在软件层次上对
中断
机制的一种模拟, 是一种异步通信方式。 -
用GCC编译过程可以被细分为四个阶段:
预编译,编译,汇编,链接
。 -
编译有线程的文件要加
-lpthread
参数。 -
父进程等待子进程的结束,可以使用的函数
wait()
和waitpid()
。 -
linux主要有两个信号安装函数,分别是什么
signal()
,sigaction()
。 -
Linux操作系统内核由
C语言
编写完成。 -
使用gdb调试程序时,next和step命令的作用?
step 就是单步执行,遇到子函数就进入并且继续单步执行;
next 是在单步执行时,在函数内遇到子函数时不会进入子函数内单步执行,而是将子 函数整个执行完再停止,也就是把子函数整个作为一步。
-
目录 /Boot 下存放linux操作系统启动时所要用到的程序
-
Linux 系统的设备文件分为三类?
块设备文件,字符设备文件,网络设备文件
-
Linux 中采用“一对一”的线程机制,也就是一个用户线程对应一个
内核线程
。 -
vim三种模式:在命令模式下按下
Esc
就进入了底线命令模式。 -
标准I/O提供了三种类型的缓冲,分别是?
全缓冲,行缓冲,不带缓冲
-
linux文件系统由四部分组成:
超级块 用于存放文件的控制信息。
引导块:在文件系统的开头,通常为一个扇区,其中存放引导程序,用于读入并启动操作系统;
超级块:用于记录文件系统的管理信息。特定的文件系统定义了特定的超级块;
inode区(索引节点):一个文件或目录占据一个索引节点。第一个索引节点是该文件 系统的根节点。利用根节点,可以把一个文件系统挂在另一个文件系统的非叶节点上;
数据区:用于存放文件数据或者管理数据。
-
一个完整的信号生命周期包含4个重要的事件,这4个重要事件分别是?
信号诞生;
信号在进程中注册完毕;
信号在进程中的注销完毕;
信号处理函数执行完毕。
-
互斥锁只有两种状态,即?
上锁,解锁
-
线程本身调用
return
函数可以退出线程。 -
向消息队列发送消息的函数是
msgsnd()
接收消息的函数是msgrcv()
。 -
系统调用可以根据文件描述符来操作文件特性。
Valgrind包括很多工具,
memcheck
是valgrind应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝大多数内存错误使用情况,cachegrind
是主要用来检查程序中缓存使用出现的问题。 memcheck ------> 这是valgrind应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝 大多数内存错误使用情况,
callgrind ------> 它主要用来检查程序中函数调用过程中出现的问题。
cachegrind ------> 它主要用来检查程序中缓存使用出现的问题。
helgrind ------> 它主要用来检查多线程程序中出现的竞争问题。
massif ------> 它主要用来检查程序中堆栈使用中出现的问题。
extension ------> 可以利用core提供的功能,自己编写特定的内存调试工具
-
信号发送函数中,
alarm函数
用于设置定时器,当计时时间到达时,向进程发送SIGALRM信号。 -
在标准IO库中,rewind函数作用?
将文件内部的位置指针重新指向一个流(数据流/文件)的开头
-
c语言中没有明确给定初值的全局变量和静态变量存放在哪儿?
全局存储区(静态存储区)
-
函数geteuid()用于得到进程的?
当前进程的实际用户UID值
-
当一个线程的属性设置为
detach
,该线程结束时立即释放它所占有的系统资源。 -
以下哪种方式属于异常终止一个进程( D)
A 从main函数返回。
B 调用exit。
C 最后一个线程从其启动例程返回。
D 接到一个信号并终止。
-
下列命令哪个是创建线程私有数据命令(A)
A pthread_key_create()
B pthread_setspecific()
C pthread_getspecific()
D pthread_key_delete();
-
下面哪种通信方式适用于不同机器之间的进程通信。( D )
A.消息队列
B.共享内存
C.信号量
D.套接字
-
创建或打开消息队列的函数为(A )
A.msgget()
B.msgsnd()
C.msgrcv()
D. msgctl()
-
什么是进程?进程资源由哪两部分组成?
进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础
进程资源包括内核空间进程资源和用户空间进程资源
-
linux中通过调用waitpid()函数得到进程的退出信息,该函数原型为
pid_t waitpid(pit_t pid, int *statloc, int options);
当第一个参数pid取值为-1时,表示(A)A 等待任一子进程退出,相当于 wait()。
B 等待进程组ID与调用进程组ID相同的任一子进程。
C 只等待进程ID等于PID的子进程。
D 等待指定进程组中的进程,该进程组id等于 pid的绝对值。
-
pid_t fork() 返回值的意义?
创建失败时返回
负数
;创建成功时返回两个值
:父进程的fork返回一个正数表示子进程的进程ID,子进程的fork返回0
-
Linux环境中使用kill函数向进程或进程组发送信号。Kill函数原型为
int kill(pid_t pid, int signo);
当第一个参数pid>0时,表示( A )A 发送信号给进程ID为pid的进程;
B 发送信号给进程组ID和该进程相同的进程;
C 发送信号给进程组内进程ID为pid的绝对值的进程;
D 发送信号给系统的所有进程;
pid>0 将信号传给进程识别码为pid 的进程。
pid=0 将信号传给和目前进程相同进程组的所有进程
pid=-1 将信号广播传送给系统内所有的进程
pid<0 将信号传给进程组识别码为pid绝对值的所有进程 -
共享主存基本操作(A )将共享主存区映射到进程虚拟地址空间。
A shmat()
B shmdt()共享内存
C shmctl()控制对共享内存的使用
D shmget() 创建共享内存
-
修改消息队列状态信息的命令是(B)
A msgsnd()发送信息
B msgctl() 控制
C msgrcv() 获取信息
D msgget() 创建
-
父进程调用wait() 可能出现的三种情况?(5分)。
如果其所有子进程都还在运行,则阻塞;
如果一个子进程已经终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回;
如果它没有任何子进程,则立即出错返回;
-
在进程中,return和exit() 的区别?
return是语言级别的,它表示了调用堆栈的返回;而exit是系统调用级别的,它表示一个进程的结束。
在main函数里,return(0)和exit(0)是一样的,子函数用return返回,而子进程用exit退出,调用exit时要调用一段终止处理程序,然后关闭所有I/O流
-
什么是孤儿进程?谁负责回收孤儿进程的内核空间资源?
孤儿进程:因父亲进程先退出而导致一个子进程被init进程收养的进程,即孤儿进程的父亲更改为init进程,该进程在孤儿进程退出后回收它的内核空间资源。
-
僵尸进程是什么?如何消灭僵尸进程?
僵尸进程:进程已经退出,但它的父亲进程还没有回收内核资源的进程,即该进程在内核空间的PCB没有释放。利用kill函数杀死父进程,僵尸函数会被init进程收养
-
简述进程对可靠信号和不可靠信号的处理过程。
如果进程在屏蔽某个信号的时间内,其他进程多次向其发送同一个信号,
不可靠信号只有一次未决记录,当进程解除屏蔽后,该信号只会被捕捉一次;
而可靠信号操作系统会记录所有的发送,当进程解除屏蔽后,操作系统会捕捉对等次数。
-
简单介绍一下信号的定义及其分类。
信号是软件中断,是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的
分类:
确定信号和随机信号;
连续信号和离散信;
周期信号和非周期信号;
能量信号与功率信号;
因果信号与反因果信号;
实信号与复信号
-
简单介绍一下匿名管道及其特点。
匿名管道用于进程之间通信,且仅限于本地父子进程之间通信,结构简单。
1)只提供单向通信,也就是说,两个进程都能访问这个文件,假设进程1往文件内写东西,那么进程2 就只能读取文件的内容。
2)只能用于具有血缘关系的进程间通信,通常用于父子进程建通信
3)管道是基于字节流来通信的
4)依赖于文件系统,它的生命周期随进程的结束结束(随进程)
5)其本身自带同步互斥效果 -
请解释一下有名管道和匿名管道的区别?
匿名管道是由pipe函数创建并打开的
命名管道是由mkfifo函数创建的 ,打开用open
命名管道和匿名管道唯一的区别就是在创建的打开,一旦这些工作完成后,它们有相同的意义。 -
什么是线程?进程和线程的区别?
进程是运行中的程序,线程是进程的内部的一个执行序列
进程是资源分配的单元,线程是执行行单元
进程间切换代价大,线程间切换代价小
进程拥有资源多,线程拥有资源少
多个线程共享进程的资源 -
Please describe the difference of signal() and sigaction() in brief
翻译为:请简单描述一下signal()和sigaction()的区别
1、signal在调用handler之前先把信号的handler指针恢复;
sigaction调用之后不会恢复handler指针,直到再次调用sigaction修改handler指针。
这样,signal就会丢失信号,而且不能处理重复的信号,而sigaction就可以。因为signal在得到信号和调用handler之间有个时间把handler恢复了,这样再次接收到此信号就会执行默认的handler。(虽然有些调用,在handler的以开头再次置handler,这样只能保证丢信号的概率降低,但是不能保证所有的信号都能正确处理)
2、signal在调用过程不支持信号block;sigaction调用后在handler调用之前会把屏蔽信号(屏蔽信号中自动默认包含传送的该信号)加入信号中,handler调用后会自动恢复信号到原先的值。
3、signal处理过程中就不能提供阻塞某些信号的功能,sigaction就可以阻指定的信号和本身处理的信号,直到handler处理结束。这样就可以阻塞本身处理的信号,到handler结束就可以再次接受重复的信号。
编程题
第一题
1.创建文件file1,写入字符串“abcdefghijklmn”;*
2.创建文件file2,写入字符串“ABCDEFGHIJKLMN”;
3.读取file1中的内容,写入file2,使file2中的字符串内容为“ ABCDEFGHIJKLMNabcdefghijklmn”
2.创建文件file2,写入字符串“ABCDEFGHIJKLMN”;
读取file1中的内容,写入file2,使file2中的字符串内容为“ ABCDEFGHIJKLMNabcdefghijklmn”
#include<stdio.h>
#include<fcntl.h>
int main(){
int fd1,fd2;
char str[14];
fd1 = open("file1.txt",O_RDWR|O_CREAT);
if(fd1 < 0)
perror("open file1 error");
write(fd1,"abcdefghijklmn",14);
lseek(fd1,0,SEEK_SET);
fd2 = open("file2.txt",O_RDWR|O_CREAT);
if(fd2 < 0)
perror("open file2 error");
write(fd2,"ABCDEFGHIJKLMN",14);
read(fd1,str,14);
write(fd2,str,14);
close(fd1);
close(fd2);
return 0;
}
第二题
1.创建新文件,该文件具有用户读写权限。
2.采用dup/dup2/fcntl复制一个新的文件描述符,通过新文件描述符向文件写入“class_name”字符串;
3.通过原有的文件描述符读取文件中的内容,并且打印显示;
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
int main(int argc,char argv[]){
int fd;
fd = open("test2.file",O_CREAT|O_WRONLY,S_IREAD|S_IWRITE);
char *name="class_name";
int fd2 = dup(fd);
if(fd2<0)
perror("dup");
write(fd2,name,strlen(name));
lseek(fd,0,SEEK_SET);
char str[12];
read(fd,str,12);
printf("%s\n",str);
close(fd);
return 0;
}
第三题
1.递归遍历/home目录,打印出所有文件和子目录名称及节点号。
2.判断文件类型,如果是子目录,继续进行递归遍历,直到遍历完所有子目录为止。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
int show (char * path){
char p[500];
DIR *dir;
struct stat statbuf;
struct dirent *dire;
lstat (path,&statbuf);
if (S_ISDIR(statbuf.st_mode)){
dir = opendir (path);
if (dir){
while( (dire = readdir(dir) ) !=NULL)
{
if(( dire ->d_name[0] )=='.')
continue;
sprintf(p,"%s/%s",path,dire->d_name);
lstat(p,&statbuf);
printf ("\t该目录文件名为: %s \n",p);
printf ("\t该目录文件节点号为: %ld \n",statbuf.st_ino);
show (p);
}
}
}
if (S_ISREG(statbuf.st_mode))//判断文件是否为常规文件
{
printf ("该文件名为: %s \n",path);//输出文件名
printf ("该文件节点号为: %ld \n",statbuf.st_ino);
}
}
int main(){
show("/home");
return 0;
}
第四题
1.打印字符串“hello world!”
2.在打印字符串“hello world!”前调用三次fork,分析打印结果。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
int i;
for(i=0;i<3;i++)
{
fork();
}
printf("hello world!!!\n");
return 0;
}
第五题
创建子进程
1.在子进程中打开文件file,写入自己的“班级_姓名_学号”,
2.父进程读取file中的内容,并且打印显示。
3.在父进程中获取已经结束的子进程的状态信息,打印该信息,并且打印结束的子进 程的进程号。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
int main(){
int fd,pid;
fd = open("file.txt",O_CREAT|O_RDWR,S_IRWXU);
if(fd< 0)
perror("open");
pid = fork();
if(pid == 0){
printf("This is the child!\n");
char str[128] = "yidongsanban_jjj_1101010";
if(write(fd,str,128) < 0)
perror("write");
exit(5);
}
else{
printf("This is the father!\n");
char buf[128];
int n,status;
if(read(fd,buf,128) < 0)
perror("read");
printf("The buf is: %s\n",buf);
if(wait(&status) < 0)
perror("perror");
if(WIFEXITED(status))
n = WEXITSTATUS(status);
else
printf("wait error!\n");
printf("The child's pid is: %d\n",pid);
printf("The child exit status is: %d\n",n);
}
return 0;
}
第六题
利用有名管道文件实现进程间通信,要求
写进程向有名管道文件写入10次“hello world”;
读进程读取有名管道文件中的内容,并依次打印。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
int main() {
int pid,fd,i;
if(mkfifo("fifotest",0666) < 0)
perror("mkfifo");
pid = fork();
if(pid < 0)
perror("fork");
else if(pid == 0) {
printf("This is the write process!\n");
int fd = open("fifotest",0666);
for(i = 0; i < 10; i++) {
if(write(fd,"hello world",12) < 0)
perror("write");
sleep(1);
}
close(fd);
} else {
char str[128];
printf("This is the read process!\n");
int fd1 = open("fifotest",0666);
for(i = 0; i < 10; i++) {
if(read(fd1,str,128) < 0)
perror("read");
else
printf("%s\n",str);
}
system("rm -f fifotest");
}
}