一、选择题
1、在安装openEuler操作系统时,( )分区强制为主分区
-
A./boot
开机:boot
-
B./swap
-
C./home
-
D./etc
2、安装openEuler操作系统时,设置引导装载程序的安装位置,默认安装在( )的MBR上
-
A./dev/hda
-
B./dev/sda
表示第一块硬盘
-
C./dev/hdb
-
D./dev/sdb
3、Linux有两种常用的引导装载程序:LILO和( )
- A.MBR
- B.GPT
- C.SCSI
- D.GRUB
4、以下哪个系统操作界面安装选项没有图形界面和网络管理功能。
- A. Desktop
- B. Minimal
- C. Basic Server
- D. Minimal Desktop
5、从图形化界面切换到命令行界面的快捷键是:
- A. Ctrl+Alt+F7
- B. Ctrl+Alt+F2
- C. win+R
- D. win+L
6、为了更好的保护系统的安全,建议用户定期使用( )命令来修改系统中相关用户的口令
- A. passwd
- B. password
- C. change
- D. key
7、( )用户可以修改任意用户的口令。
- A.administrator
- B. root
- C.user
- D.special user
8、openEuler的登陆界面有两种:( )界面和图形化界面
- A.桌面化
- B.命令行
- C.操作行
- D.管理化
9、若要安装图形化操作界面,安装时的选项应该是:
- A. Basic Server
- B. Minima
- C. Desktop
10、下列变量名中有效的shell变量名是( )。
- A.-2-time
- B.2$3
- C.trust_no_1
- D.2004file
11、下面哪个文件包含bash默认的环境变量( )
-
A.~/.profile
用户环境变量
-
B./bash
-
C./etc/profile
默认环境变量
-
D.~/bash
12、当字符串用单引号’ ’括起来时,SHELL将( )。
-
A.解释引号内的特殊字符
-
B.执行引号中的命令
-
C.不解释引号内的特殊字符
字符串原样输出
-
D.结束进程
13、一个bash shell脚本的第一行是( )。
- A.!#/bin/bash
- B. #/bin/bash
- C. /bin/bash
- D. #!/bin/bash
14、下面哪个命令是用来定义shell的全局变量( )
- A. Exportfs
- B. alias
- C.exports
- D.export
15、系统配置文件,一般来说大部分位于( )目录下。
-
A. /boot
-
B./etc
etcetera:系统配置信息存放目录
-
C./home
-
D./usr
16、若当前目录为/home,命令ls -l将显示home目录下的( )。
- A.所有文件
- B.所有隐含文件
- C.所有非隐含文件
- D.文件的具体信息
17、你使用命令 "vi /etc/inittab”查看该文件的内容,你不小心改动了一些内容,为了防止系统出问题,你不想保存所修改内容,你应该如何操作( )
-
A.在未行模式下,键入:wq
-
B.在末行模式下,键入:q!
对于已经修改过的文件要加上
!
表示强制退出 -
C.在末行模式下,键入:x!
-
D.在编辑模式下,键入“ESC”键直接退出vi
18、如果您想列出当前目录以及子目录下所有扩展名为“.txt”的文件,那么您可以使用的命令是
-
A. ls *.txt
*
:通配符 -
B.find -name “.txt”
-
C.ls -d .txt
-
D. find . “.txt”
19、用ls -al 命令列出下面的文件列表,( )文件是符号连接文件
-
A.-rw-rw-rw-2 hel users 56 sep 09 11:05 hello
-
B.-rwxrwxrwx 2 hel users 56 Sep09 11:05 goodbey
-
C.drwxr–r–1 hel users 1024 Sep 10 08:10 zhang
-
D.lrwxr–r–1 hel users 2024 sep 12 08:12 cheng
-
:表示目录d
: 表示文件l
:表示链接(LINK)
20、Linux三种特殊权限中仅用于目录文件的权限是( )
- A.SUID
- B.SGID
- C.黏滞位SBIT
- D.都可以
21、若要将当前目录中的myfile.txt文件压缩成myfile.txt.tar.gz,则实现的命令为
- A.tar -cvf myfile.txt myfile.txt.tar.gz
- B.tar -zcvf myfile.txt myfile.txt.tar.gz
- C.tar -zcvf myfile.txt.tar.gz myfile.txt
- D.tar -cvf myfile.txt.tar.gz myfile.txt
22、下列哪个命令在建立一个 tar归档文件的时候列出详细列表( )。
- A. tar -t
- B.tar -cv
- C.tar -cvf
- D.tar -r
23、可以用来对文件xxx.gz解压缩的命令是( )。
- A.compress
- B.uncompress
- C.gunzip
- D. tar
24、对文件进行归档的命令为( )
- A. Gzip
- B. tar
- C. dump
- D. dd
25、若要对myfile.txt.tar.gz包进行解压还原,则应使用命令( )来实现。
- A.tar -xvf myfile.txt.tar.gz
- B.tar -cvf myfile.txt.tar.gz
- C.tar -zcvf myfile.txt.tar.gz
- D.tar -zxvf myfile.txt.tar.gz
26、以下哪项不属于单处理机系统中多道程序运行时的特点?
- A.多道程序被同时存放在内存中
- B.宏观上并行执行
- C.微观上并行执行
- D.微观上串行执行
27、以下哪个操作系统不属于分时操作系统?
- A. RedHat
- B. Windows
- C.VxWorks
- D.Android
28、操作系统是一组____
- A.文件管理程序
- B.资源管理程序
- C.中断处理程序
- D.设备管理程序
29、以下哪项不是操作系统关心的主要问题?
- A.管理计算机裸机
- B.设计、提供用户程序与计算机硬件系统的界面
- C.管理计算机系统资源
- D.高级程序设计语言的编译器
30、下列关于操作系统的叙述正确的是?
- A.操作系统是硬件和软件之间的接口
- B.操作系统是主机与外设之间的接口
- C.操作系统是用户与计算机之间的接口
- D.操作系统是源程序与目标程序之间的接口
31、在Linux系统中,根用户登录后,其当前目录为__,普通用户wang登录后,一般情况下,其当前目录为
- A./home; /root;
- B./root; /home/wang;
- C./root; /etc;
- D./etc;/home/wang;
32、除了易用性、高效性、可靠性和可扩展性这四个设计目标,现代操作系统还应考虑能效性。以下哪于操作系统改善计算机能耗的途径?
- A.根据工作负载调整CPU频率
- B.采用模块化的结构设计
- C.采用动态电压和频率缩放技术
- D.休眠或关闭部分空闲设备(如磁盘)
33、哪个目录存放用户密码信息( )
-
A. /boot
-
B./etc
etcetera:系统配置信息存放目录
-
C. /var
-
D. /dev
34、openEuler一般被用作哪一类操作系统?
- A.个人计算机操作系统
- B.智能移动终端操作系统
- C.轻量级嵌入式操作系统
- D.服务器操作系统
35、默认情况下管理员创建了一个用户,就会在( )目录下创建一个用户主目录。
- A./usr
- B./home
- C./root
- D./etc
36、__目录用来存放系统管理员使用的管理程序。
-
A. /sbin;
superBin
-
B./bin;
-
C. /root;
-
D. /home;
37、以下哪一种指令显示的结果为$openEuler?
- A.\echo $openEuler
- B.echo “$openEuler”
- C.echo ‘$openEuler’
- D.echo “${openEuler}”
38、若要结束进程,应使用( )命令。
- A. kill
- B.ps
- C. pss
- D. pstree
39、一个Bash Shell脚本的第1行是什么?
- A. #!/bin/bash
- B. #/bin/bash
- C.#/bin/csh
- D. /bin/bash
40、哪个符号加在命令后面可以在后台执行程序(选择最合适的答案)
- A. @
- B.&
- C.#
- D.*
41、以下哪个命令可以将普通用户转换成超级用户?
- A.super
- B. passwd
- C. tar
- D.su
42、终止一个前台进程可能用到的命令和操作是( )
-
A. Kill
-
B.+C
此处应为 CTRL+C 代表强制结束当前前台进程
-
C.shut down
-
D. halt
43、在一行内运行多个命令需要用什么字符隔开?
- A. @
- B. $
- C.;
- D.*
44、下面哪一个选项不是Linux系统的进程类型:( )
- A.交互进程
- B.批处理进程
- C.守护进程
- D.就绪进程
45、哪个命令显示当前系统运行的进程列表?( )
- A. ps -ax
- B.proc -a
- C. stat
- D. ls
46、在终端中执行echo"current path:" ‘pwd’ ",结果是?
- A. path:‘/home/openEuler’
- B.current
- C.current path:‘pwd’
- D.current path: pwd
47、临界区是指并发进程中涉及共享变量的( )
- A.程序段
- B.管理信息区
- C.公共数据区
- D.信息存储区
48、下列有关fork( )函数返回值说法错误的是( )
-
A.函数成功返回时,一次返回两个值,错误返回时为-1
-
B.返回值等于0表示子进程
-
C.返回值大于0表示父进程
-
D.大于0返回值为父进程的PID号
大于0返回值为子进程PID号
49、LINUX交换分区的格式为( )。
-
A.ext2
-
B.ext3
-
C.FAT
-
D.swap
swsp:交换
50、下面程序的输出是什么( )
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv)
if(fork() == 0)
printf("hello");
else
printf("world");
return 0;
- A.helloworld
- B. wordhello
- C. Hello
- D.不确定
51、以下对磁盘文件管理的描述,不正确的是( )。
- A.在Linux图形化桌面环境中,使用文件浏览管理器来实现对磁盘或文件的管理。
- B.对磁盘或文件的管理,很多情况下均可使用快捷菜单来实现对其操作。
- C.文件浏览管理器提供有文件搜索功能。
- D.文件浏览管理器中,无法实现对U盘的格式化操作。
52、下面说法不正确的是( )
-
A.管道和命名管道是最早进程间通信机制之一
-
B.消息队列是将消息按队列的方式组织成的链表,每个消息都是其中的一个节点
-
C.进程创建一般由create函数完成
进程创建使用Fork()函数
-
D.共享内存和消息都是由Linux内核来管理和分配资源
53、光盘所使用的文件系统类型为( )
- A. ext2
- B. ext3
- C.swap
- D.ISO 9660
54、关于SIGCHLD信号说法错误的是( )
- A.在子进程退出时,会向父进程发送该信号
- B.需要及时处理SIGCHLD防止僵尸进程
- C.SIGCHLD信号的默认处理方式是忽略
- D.由于SIGCHLD信号默认方式是忽略,所以在代码中不需要手动设置SIGCHLD信息的处理方式,也不会产生僵尸进程
55、下列哪种通信方式只能用于具有亲缘关系进程之间的通信( )
- A.匿名管道
- B.消息队列
- C.共享内存
- D.命名管道
56、显示已经挂装的文件系统磁盘inode使用状况的命令是( )?
- A. df -i
- B. su -I
- C. du -I
- D.free -i
57、线程使用以下哪种方式退出时,无法保证不结束整个进程?
-
A.从启动例程中返回
-
B.线程执行exec函数后,导致当前进程地址空间全部更新
地址更新导致失去PCB
-
C.调用pthread_exit
-
D.被统一进程的其他线程取消
58、以下说法正确的是( )。
-
A.只有用户级线程的操作系统中,调度以线程为单位,由操作系统控制进程中的多个线程运行。
-
B.只有用户级线程的操作系统中,调度以进程为单位,由操作系统控制进程中的多个线程运行。
-
C.只有用户级线程的操作系统中,调度以进程为单位,由用户程序控制进程中的多个线程运行。
用户级线程,线程由用户代码实现,操作系统看不到进程
-
D.只有用户级线程的操作系统中,调度以线程为单位,由用户程序控制进程中的多个线程运行。
59、调用pthread_create函数创建一个线程后,( )会先运行。
-
A.该进程的主线程
-
B.调用pthread_create函数的线程
-
C.创建的新线程或调用pthread_create函数的线程
分时操作系统程序异步执行
-
D.创建的新线程
60、假设U盘的设备名为/dev/sdb,现要将U盘格式化为FAT分区,以下命令中不能实现的是( )
-
A. mkfs.vfat /dev/sdb
该命令为格式化FAT格式系统应为正确选项
-
B.mkfs.msdos /dev/sdb
-
C.mkdos /dev/sdb
无效命令
-
D.mkfs.ext3 /dev/sdb
该命令为格式化EXT3格式系统应为不能实现选项
😥此题暂时保留,已反馈老师,无回应则照题库作答
61、一个MBR硬盘最多能够被分成___个主分区。
- A.1
- B.2
- C.3
- D.4
62、以下对于vi编辑器用法的描述,不正确的是( )。
-
A.插入模式下,按ESC键,可进入命令模式
-
B.在命令模式下,输入3dd,可立即删除从当前光标所在行开始的后面连续3行的内容
-
C.当用户对内容做了一些编辑修改后,若要放弃修改退出,则按Esc键返回命令模式,然后输入:q并回车退出
对于已经修改过的文件要加上
!
表示强制退出 -
D.在命令模式按i键,可进入插入(编辑修改)模式
63、以下关于线程清理函数的说法,错误的是( )。
- A.线程从其代码中的return语句结束时,会引发pthread_cleanup_push和pthread_cleanup_pop函数执行
- B.pthread_cleanup_push和pthread_cleanup_pop函数都是以宏的形式实现的
- C.线程从其代码中的pthread_exit函数结束时,会引发pthread_cleanup_push和pthread cleanup_pop函数执行
- D.pthread_cleanup_push和pthread_cleanup_pop函数必须成对使用
64、在vi编辑器中的命令模式下,撤销上一次操作,可使用( )命令。
- A.上箭头
- B.下箭头
- C.backspace
- D.u
65、以下不属于线程同步机制的是( )。
- A.正则表达式
- B.互斥锁
- C.读写锁
- D.条件变量
66、以下关于互斥锁的描述,错误的是( )。
-
A.若线程申请的互斥锁正被其他线程占用,则该线程将被挂起
阻塞是低级调度,挂起是中级调度
-
B.互斥锁的操作具有原子性
-
C.互斥锁可以用来锁定资源或进程
进程不可以被锁定
-
D.互斥锁也是一种信号量
67、以下函数中,( )是用于互斥锁上锁的。
- A. pthread_cond_signal
- B.pthread_rwlock_rdlock
- C. Pthread_mutex_lock
- D. pthread_spin_init
68、在openeuler系统中,下列哪个命令可以用来建立分区:
- A. fdisk
- B. mkfs
- C.tune2fs
- D.mount
69、以下( )步骤是正确的。
①对互斥量加锁
②改变互斥量保护的条件
③给等待条件的线程发信号
④对互斥量解锁
- A.①②③④
- B.①②④③
- C.②③①④
- D.③④①②
70、在openeuler系统中,下列哪个命令可以用来将分区挂载到目录:( )
- A. fdisk
- B. mkfs
- C.tune2fs
- D.mount
71、比较文件的差异要用到的命令是以下哪一种?
-
A. diff
差异:difference
-
B. cat
-
C. wc
-
D.head
72、将某分区(hda1)挂载到Linux文件系统的/winsys目录下,命令是( )。
-
A. mount dev/hda1 /winsys
-
B. mount /dev/hda1 /winsys
/
:代表根目录 没有斜杠代表当前目录 -
C.mount /dev/hda1 winsys
-
D.mount dev/hda1 winsys
73、存放设备文件的相关文件目录是?
-
A. /dev
设备:device
-
B./etc
-
C./lib
-
D./bin
74、rm命令表示什么?
-
A.文件复制命令
-
B.移动文件命令
-
C.文件内容统计命令
-
D.文件删除命令
删除:remove
75、在openEuler系统中,用户文件描述符0表示?
- A.标准输出设备文件描述符
1
- B.标准输入设备文件描述符
0
- C.管道文件描述符
|
- D.标准错误输出设备文件描述符
2
76、在使用mkdir命令创建新的目录时,在其父目录不存在时先创建父目录的选项是?
-
A. -d
-
B. -m
-
C. -P
parents:父
-
D. -f
77、执行命令“chmod o+rw myfile”后,myfile文件的权限变化为?
- A.所有用户都可读写myfile文件
- B.其他用户可读写myfile文件
- C.同组用户可读写myfile文件
- D.文件所有者读写myfile文件
78、以下不是用来分配内存的函数的是?
-
A. realloc()
-
B. malloc()
-
C.free()
释放内存
-
D. calloc()
79、lseek()中第三个参数的值为0表示?
- A.文件读写指针当前位置
- B.文件开始位置
- C.文件结束位置
- D.都不是
lseek()函数的三个参数含义如下:
- 文件描述符:这是第一个参数,用于指定要操作的文件。在Unix/Linux系统中,每个打开的文件都有一个唯一的文件描述符,它是一个非负整数。
- 偏移量:这是第二个参数,表示需要移动到的新位置相对于第三个参数指定的参照点的偏移量。偏移量可以是正数(向后移动)或负数(向前移动)。
- 参照点:这是第三个参数,用于指定偏移量的起始点。它有三个可能的值:
- SEEK_SET:从文件开始处计算偏移量。如果偏移量为0,则指向文件的起始位置。
- SEEK_CUR:从当前文件指针位置计算偏移量。如果之前没有使用过lseek(),效果与SEEK_SET相同。
- SEEK_END:从文件末尾计算偏移量。如果偏移量为0,则指向文件的末尾
- 0:开始
80、下面更改文件命令只能更改符号连接的目标文件的权限的命令是?
- A.chgrp
- B.chown
- C.chmod
- D.以上都不对
81、下面关于ftell()函数成功调用说法不正确的是?
- A.返回读写指针当前相对文件起始位置的位移量
- B.返回读写指针当前相对文件结束位置的位移量
- C.会清除流结束标志
- D.会撤销已调用ungetc()对流的影响
82、在linux系统中,重新启动可使用( )命令。
- A.ctrl+alt+del
- B. halt
- C.shutdown -h
- D. reboot
83、以下函数中表示从某流中读取一个字符但该函数不带参数,表示从标准输入流中读字符的函数是?
- A. Getc
- B. gets
- C.fgec
- D. getchar
84、在函数fopen()中文件打开模式中不是可读写的方式打开文件模式是?
- A.r
- B.r+
- C.a+
- D.w+
85、格式化输出可把格式化数据输出到标准输出、指定文件及字符缓冲区。其中( )函数是将格式化数据输出到指定大小的字符缓冲区?
-
A.sprintf
这个函数用于将格式化的数据写入一个字符串缓冲区。然而,它不会检查目标缓冲区的大小,因此如果提供的缓冲区太小,可能会导致缓冲区溢出,从而引发安全问题
-
B.snprintf
与sprintf类似,但snprintf允许指定最大写入的字符数(包括终止的空字符)。这有助于防止缓冲区溢出,提高代码的安全性
-
C. fprintf
这个函数用于将格式化的数据输出到指定的文件流中。它通常用于将数据写入文件或标准输出(如stdout)
-
D. printf
这个函数用于将格式化的数据输出到标准输出(通常是屏幕)。它常用于调试和显示程序运行结果
86、.以下选项中,哪个命令可以关机?
-
A. init 0
关机
-
B. init 1
单用户模式
-
C. init 5
多用户模式
-
D. init 6
重启
87、以下选项中,哪个命令可以重启?( )
- A. init 0
- B.init 1
- C.init 5
- D.init 6
88、字符界面下使用shutdown命令重启计算机时所用的参数是( )
- A. -h
- B.-t
- C.-k
- D.-r
89、使用vi编辑器时,命令"dd"用来删除当前的( )
- A.行
- B.变量
- C.字
- D.字符
90、vi中哪条命令是不保存强制退出( )
- A.:wq
- B.:wq!
- C.:q!
- D.:quit
二、多选题
1、操作系统的安装有多种方式:
-
A.光盘安装
-
B.软盘安装
太小了装不下
-
C.U盘安装
2、在手工操作时期,用户可以使用哪些介质将程序或数据输入计算机?
- A.光盘
- B.纸带
- C.卡片
- D.U盘
3、在批处理系统时代(晶体管时代),批处理方式有哪些?
- A.联机批处理
- B.多道批处理
- C.脱机批处理
- D.并行批处理
4、实时操作系统的主要特点包括?
- A.多路性
- B.独占性
- C.及时响应
- D.高可靠性
5、内存管理的主要任务有?
- A.物理内存的分配和回收
- B.虚拟地址到物理地址的映射
- C.地址转换的加速
- D.突破物理内存限制
6、openEuler的优势体现在?
- A.多核调度技术
- B.软硬件协同
- C.轻量级虚拟化
- D.指令级优化
- E.智能化引擎
三、操作题
1、信号量IPC操作考查
#include <errno.h>
#define MAX_SEMAPHORES 5
#include <stdio.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <errno.h>
#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++ )
{
/*请调用semctl函数,读取并输出与上述数组输出相同的输出*/
printf("Semaphore %d, value %d\n", i, sem_read_array[i] );
}
ret = semctl( semid, 0, IPC_RMID );
}
else
printf("Could not allocate semaphore (%d)\n", errno);
return 0;
}
2、消息队列IPC操作考察
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<string.h>
#include<sys/msg.h>
#define BUFSIZE 128
struct msg_buf
{
long type;
char msg[BUFSIZE];
};
int main(int argc,char *argv[])
{
key_t key;
int msgid;
struct msg_buf msg_snd,msg_rcv;
struct msginfo buf;
char *ptr="helloOpenEuler";
memset(&msg_snd,'\0',sizeof(struct msg_buf));
memset(&msg_rcv,'\0',sizeof(struct msg_buf));
msg_rcv.type=1;
msg_snd.type=1;
memcpy(msg_snd.msg,ptr,strlen(ptr));
if((key=ftok(".",'A'))==-1)
{
perror("ftok");
exit(EXIT_FAILURE);
}
if((msgid=msgget(key,0600|IPC_CREAT))==-1)
{
perror("msgget");
exit(EXIT_FAILURE);
}
printf("msgsnd_return=%d\n",msgsnd(msgid,(void *)&msg_snd,strlen(msg_snd.msg),0));
msgctl(msgid,MSG_INFO,&buf);
/*请分别输出buf.msgmax= buf.mnb= buf.msgpool= buf.msgmap= buf.msgmni= buf.msgssz= buf.msgtql= buf.msgseg= 每个之间换行隔开*/
printf("buf.msgmax=%d\nbuf.msgmnb=%d\nbuf.msgpool=%d\nbuf.semmap=%d\nbuf.msgmni=%d\nbuf.msgssz=%d\nbuf.msgtql=%d\nbuf.msgseg=%d\n",buf.msgmax,
buf.msgmnb,buf.msgpool,buf.msgmap,buf.msgmni,buf.msgssz,buf.msgtql,buf.msgseg);
printf("msgrcv_return=%d\n",msgrcv(msgid,(void *)&msg_rcv,BUFSIZE,msg_rcv.type,0));
/*输出msg_rcv.msg= 即收到的消息*/
printf("msg_rcv.msg=%s\n",msg_rcv.msg);
printf("msgctl_return=%d\n",msgctl(msgid,IPC_RMID,0));
}
3、文件的读写
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#define BUFFER_SIZE 1024
//请不要更改文件路径!!!
#define SRC_FILE_NAME "/data/workspace/myshixun/fileSystem/src/fileProgram/src_file"
//请不要更改文件路径!!!
#define DEST_FILE_NAME "dest_file"
#define OFFSET 10240
int main()
{
int src_file,dest_file;
unsigned char buff[BUFFER_SIZE];
int real_read_len;
//请在此处填入代码,使用合适的模式打开源目标SRC_FILE_NAME文件
src_file = open(SRC_FILE_NAME,O_RDONLY);
//请在此处填入代码,使用合适的模式打开写入文件目标DEST_FILE_NAME文件,需要考虑到文件是否存在?
dest_file = open(DEST_FILE_NAME, O_WRONLY | O_CREAT);
//dest_file = open(DEST_FILE_NAME, O_WRONLY | O_CREAT | O_TRUNC);
if(src_file < 0 || dest_file < 0)
{
printf("Open file error!\n");
exit(1);
}
//请在此处填入代码,设置偏移量读取文件最后10KB数据
lseek(src_file,-OFFSET,SEEK_END);
while((real_read_len = read(src_file,buff,sizeof(buff))) > 0)
{
//请在此处填入代码,使用buff写入目标文件
write(dest_file,buff,real_read_len);
}
close(dest_file);
close(src_file);
return 0;
}
4、读文件系统函数
#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;
}
5、openEuler初体验
第一关
#!/bin/bash
#在以下部分写出完成任务的命令
#*********begin*********#
cd /
ls -a
#********* end *********#
第二关
#!/bin/bash
#在以下部分写出完成任务的命令
#*********begin*********#
rm -rf newfile
touch newfile
mkdir newdir
mv newfile newdir/newfileCpy
#********* end *********#
第三关
#!/bin/bash
#在以下部分写出完成任务的命令
#*********begin*********#
man 3 fopen
#********* end *********#
6、openEuler 文件/目录管理
openEuler之文件创建/删除
#!/bin/bash
#在以下部分写出完成任务的命令
#***********begin*************#
touch file1 file2
rm -rf oldFile1 oldFile2
#************end**************#
openEuler之目录创建/删除
#!/bin/bash
#在以下部分写出完成任务的命令
#***********begin*************#
mkdir newDir1 newDir2
rm -rf oldDir1 oldDir2
#************end**************#
openEuler之文件复制/重命名
#!/bin/bash
#在以下部分写出完成任务的命令
#***********begin*************#
cp file1 ./Dir
cp file2 ./Dir
cp file1 ./Dir/file1Cpy
mv file3 ./Dir
mv file4 ./Dir
mv file5 file6
#************end**************#
openEuler之目录复制/重命令
#!/bin/bash
#在以下部分写出完成任务的命令
#***********begin*************#
cp -r Dir1 ./Dir
cp -r Dir2 ./Dir
cp -r Dir1 ./Dir/Dir1Cpy
mv Dir3 ./Dir
mv Dir4 ./Dir
mv Dir5 Dir6
#************end**************#
openEuler之文件/目录内容查看
#!/bin/bash
#在以下部分写出完成任务的命令
#***********begin*************#
cat file1
head -5 file2
tail -5 file2
ls -a /home
#************end**************#
7、openeuler 文件/目录高级管理一
openEuler文件权限修改
#!/bin/bash
#在以下部分写出完成任务的命令
#***********begin*************#
chmod u=x oldFile1
chmod g-w oldFile2
chmod o+x oldFile3
chmod u=r,g=w,o=x oldFile4
#************end**************#
openEuler目录权限修改
#!/bin/bash
#在以下部分写出完成任务的命令
#***********begin*************#
chmod u=x oldDir1
chmod g-w oldDir2
chmod o+x oldDir3
chmod u=r,g=w,o=x oldDir4
chmod -R u=r,g=w,o=x oldDir5
#************end**************#
openEuler修改文件/目录所有者
#!/bin/bash
#在以下部分写出完成任务的命令
#***********begin*************#
chown oldUser oldFile
chown oldUser oldDir1
chown -R oldUser oldDir2
#************end**************#
openEuler文件/目录所属组修改
#!/bin/bash
#在以下部分写出完成任务的命令
#***********begin*************#
chgrp oldGroup oldFile
chgrp oldGroup oldDir1
chgrp -R oldGroup oldDir2
#************end**************#
8、openEuler之文件/目录搜索
查询命令-which/whereis
#!/bin/bash
#在以下部分写出完成任务的命令
#***********begin*************#
which useradd
whereis useradd
whereis -m useradd
#************end**************#
查询命令-find
find . -name "*.conf"
find . -name "my*"
find /root -size +1M
find /root -name "*.Link" -a -type l
9、openEuler之用户管理
创建/删除新用户
#!/bin/bash
#在以下部分写出完成任务的命令
#***********begin*************#
sudo useradd -m newUser
sudo userdel -r oldUser
cd /home/newUser
pwd
#************end**************#
openEuler 用户密码管理
#!/bin/bash
#创建newUser新用户
#***********begin*************#
useradd newUser
#************end**************#
#在符号<<前输入设置用户密码的命令(命令与<< EOF保持在同一行), 密码输入在下一行,确认密码输入在下下行
#例如:
#command << EOF
#password
#password
#EOF
#***********begin*************#
passwd newUser << EOF
123456
123456
EOF
#************end**************#
openEuler用户权限切换
#!/bin/bash
#创建newUser新用户
#***********begin*************#
useradd newUser
#************end**************#
#在符号<<前输入设置用户密码的命令(命令与<< EOF保持在同一行), 密码输入在下一行,确认密码输入在下下行
#例如:
#command << EOF
#password
#password
#EOF
#***********begin*************#
passwd newUser << EOF
123456
123456
EOF
#************end**************#
#使用su命令切换当前用户身份为newUser,并且执行whoami指令,然后恢复原来的身份;
#提示使用su命令的-c参数完成
#***********begin*************#
su newUser -c whoami
#************end**************#
10、openEuler之用户高级管理
创建/删除用户组
#!/bin/bash
#在以下部分写出完成任务的命令
#***********begin*************#
groupadd newGroup
groupadd -g 1010 newGroupID
groupdel oldGroup
#************end**************#
openEuler用户所属组变更
#!/bin/bash
#在以下部分写出完成任务的命令
#***********begin*************#
useradd newUser
usermod -a -G oldGroup newUser
#************end**************#
openEuler用户/用户组编辑
#!/bin/bash
#在以下部分写出完成任务的命令
#***********begin*************#
usermod -l newName oldName
usermod -d /home/newName newName
groupmod -n newGroup oldGroup
#************end**************#
11、查看进程
#!/bin/bash
#在以下部分写出完成任务的命令
#*********begin*********#
ps -aux
ps -aux|grep php
ps -u root
pstree
#********* end *********#
12、创建进程
#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
void main()
{
int p1,i;
while((p1=fork())==-(1);
if (p1>0)
for (i=0;i<5;i++)
{
printf("I am parent.\n");
sleep(1);
}
else
for(i=0;i<5;i++)
{
printf("I am child.\n");
sleep(1);
}
}
13、进程同步原理
1、P、V 操作中,P 操作的作用是? ABB ACA
A、请求资源并可能阻塞 √
B、释放资源并唤醒进程
C、检查信号量值并打印
D、初始化信号量
2、信号量的值小于 0 时,表示什么?
A、当前可用资源的数量
B、等待使用该资源的进程个数(绝对值)√
C、没有进程在等待资源
D、信号量被错误设置
3、在信号量机制中,当信号量的值为 -3 时,表示什么?
A、有 3 个资源可用
B、有 3 个进程正在等待资源 √
C、进程处于阻塞状态
D、进程处于就绪状态
4、在 openEuler 中,semget 函数用于?
A、创建或访问一个信号量集 √
B、对信号量执行 P 或 V 操作
C、阻塞父进程,子进程执行
D、获取与路径相对应的键值
5、以下哪个函数用于唤醒等待信号量的进程?
A、semop
B、semctl
C、wakeup(在 P、V 操作实现中) √
D、ftok
6、在进程同步原语中,wait() 函数的作用是?
A、阻塞父进程,子进程执行 √
B、创建或访问信号量集
C、对信号量执行 P 操作
D、获取与路径相对应的键值
14、进程通信
信号与管道
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#define TRUE 1
#define FALSE 0
#define SIZE 11
typedef int QueueData; //定义一个整型变量 QueueData,与为基本数据类型定义新的别名一样
//任务:定义队列结构体
/*********begin***********/
typedef struct _queue{
int data[SIZE];
int front;
int rear;
}Queue;
/**********end************/
//任务:信号量结构体
/*********begin***********/
struct data{
sem_t count;
Queue q;
};
struct data sem;
/**********end************/
pthread_mutex_t mutex; //互斥变量使用特定的数据类型
int num = 0;
int InitQueue(Queue *q) {
//任务:队列初始化
/*********begin***********/
if(q==NULL){
return FALSE;
}
q->front=0;
q->rear=0;
return TRUE;
/**********end************/
}
int QueueEmpty(Queue *q) {
//任务:判断空队情况
/*********begin***********/
if(q==NULL){
return FALSE;
}
return q->front==q->rear;
/**********end************/
}
int QueueFull(Queue *q) {
//任务:判断队满的情况
/*********begin***********/
if(q==NULL){
return FALSE;
}
return q->front==(q->rear+1)%SIZE;
/**********end************/
}
int DeQueue(Queue *q, int &x) {
//任务:出队函数
/*********begin***********/
if(q==NULL){
return FALSE;
}
if(QueueEmpty(q)){
return FALSE;
}
q->front=(q->front+1)%SIZE;
x=q->data[q->front];
return TRUE;
/**********end************/
}
int EnQueue(Queue *q, int x) {
//任务:进队函数
/*********begin***********/
if(q==NULL){
return FALSE;
}
if(QueueFull(q)){
return FALSE;
}
q->rear=(q->rear+1)%SIZE;
q->data[q->rear]=x;
return TRUE;
/**********end************/
}
void* Producer(void* arg) {
//任务:设置生产者线程
/*********begin***********/
int i=0;
while(i<10){
i++;
int time=rand()%10+1;
usleep(time*100000);
sem_wait(&sem.count);
pthread_mutex_lock(&mutex);
if(!QueueFull(&sem.q)){
num++;
EnQueue(&sem.q,num);
printf("produce a message, count=%d\n",num);
}
else printf("Full\n");
pthread_mutex_unlock(&mutex);
sem_post(&sem.count);
}
printf("i(producer)=%d\n",i);
/**********end************/
}
void* Customer(void* arg) {
//任务:设置消费者线程
/*********begin***********/
int i=0;
while(i<10){
i++;
int time=rand()%10+1;
usleep(time*100000);
sem_wait(&sem.count);
pthread_mutex_lock(&mutex);
if(!QueueEmpty(&sem.q)){
num--;
DeQueue(&sem.q,num);
printf("consume a message, count=%d\n",num);
}
else printf("Empty\n");
pthread_mutex_unlock(&mutex);
sem_post(&sem.count);
}
printf("i(customer)=%d\n",i);
/**********end************/
}
int main() {
//任务:完善主函数
/*********begin***********/
srand((unsigned int)time(NULL));
sem_init(&sem.count,0,10);
pthread_mutex_init(&mutex,NULL);
InitQueue(&(sem.q));
pthread_t producid;
pthread_t consumid;
pthread_create(&producid,NULL,Producer,NULL);
pthread_create(&consumid,NULL,Customer,NULL);
pthread_join(consumid,NULL);
sem_destroy(&sem.count);
pthread_mutex_destroy(&mutex);
return 0;
/**********end************/
}
涉及的系统调用
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
int pipefd[2];
pid_t p1, p2;
char buffer[1024];
ssize_t bytesRead;
// 创建管道
if (pipe(pipefd) == -1) {
perror("pipe");
return 1;
}
// 创建第一个子进程 p1
p1 = fork();
if (p1 < 0) {
perror("fork");
return 1;
} else if (p1 == 0) { // 子进程 p1
close(pipefd[0]); // 关闭读端
const char *msg = "child1 process is sending message!\n\n";
write(pipefd[1], msg, strlen(msg));
close(pipefd[1]); // 关闭写端
return 0;
}
// 创建第二个子进程 p2
p2 = fork();
if (p2 < 0) {
perror("fork");
return 1;
} else if (p2 == 0) { // 子进程 p2
close(pipefd[0]); // 关闭读端
const char *msg = "child2 process is sending message!\n\n";
write(pipefd[1], msg, strlen(msg));
close(pipefd[1]); // 关闭写端
return 0;
}
// 父进程
close(pipefd[1]); // 关闭写端
while ((bytesRead = read(pipefd[0], buffer, sizeof(buffer) - 1)) > 0) {
buffer[bytesRead] = '\0'; // 确保字符串以 null 结尾
printf("%s", buffer);
}
close(pipefd[0]); // 关闭读端
// 等待子进程结束
waitpid(p1, NULL, 0);
waitpid(p2, NULL, 0);
return 0;
}
15、条件判断与循环结构
if语句
if [ $current_pod_num -gt 140 ]
then
echo "pod数量为$current_pod_num,自动增加三台k8s集群节点"
elif [ $current_pod_num -ge 90 ]
then
echo "pod数量为$current_pod_num,自动增加一台k8s集群节点"
else
echo "pod数量为$current_pod_num,不需要增加k8s集群节点"
fi
case语句
1、已经脚本/home/a.sh的内容如下:
name=$1
case $name in
www.baidu)
echo "三级域名"
educoder.net)
echo "二级域名"
net)
echo "主机名"
esac
在终端执行bash /home/a.sh "www.baidu",以下说法正确的是:
A、屏幕输出内容为"三级域名”。
B、屏幕输出内容为"二级域名”。
C、屏幕输出内容为"主机名”。
D、屏幕输出错误,异常。 √
2、已知道/opt/a.sh的脚本内容如下:
#!/bin/bash
name=$1
case $name in
[0-9a-zA-Z])
echo "字母或者数字"
;;
[0-9])
echo "数字"
;;
0|4)
echo "0或者4"
;;
*)
echo "路过"
;;
esac
在终端执行bash /home/a.sh 4,下面说法正确的是:
A、输出结果为“0或者4”,因为输入的数字4,正则优先匹配到 0|4这个条件。
B、输出结果为“数字”, 因为输入的数字4,正则优先匹配到[0-9]的条件。
C、输出结果为“字母或者数字”,因为输入的数字4,正则优先匹配到[0-9a-zA-Z]的条件。 √
D、输出结果为“pass”, 因为输入的数字4,正则优先匹配到 * 的条件。
for命令
for i in `seq 1 2 10`
do
echo "1~10之间的奇数分别是:-->$i"
done
while命令
1、已知脚本/home/a.sh内容如下:
#!/bin/bash
while true
do
uptime >> /tmp/uptime.log
sleep 4
done
在用户终端执行bash /home/a.sh & 命令下列说法正确的是:
A、a.sh脚本会一直在linux后台执行 √
B、a.sh脚本会一直在screen端执行
C、a.sh脚本不会执行因为他没有执行权限
D、程序无输出,因为脚本没有执行权限
2、这段脚本输出结果为
#!/bin/bash
a=3
b=4
c=$a+$b
echo $c
A、输出结果为7
B、输出结果为3+4 √
C、输出结果为$a+$b
3、这段脚本输出结果为
#!/bin/bash
a=3
b=4
c=$((a+b))
echo $c
A、7 √
B、a+b
C、3+4
D、空
4、已知脚本/home/a.sh内容如下:
a=1
b=2
while (($a+$b))
do
echo 10
sleep 101
done
在终端执行 bash /home/a.sh输出的结果为:
A、脚本程序会报错。
B、程序无输出,因为判断条件不为true。
C、每隔十秒钟输出数字10到终端。 √
D、程序无输出,因为脚本没有执行权限
循环语句嵌套
dir="/usr/games"
for folder in $dir
do
for file in $folder/*
do
if [ -x $file ]
then
echo " $file"
fi
done
done
四、组合题
1、读写锁
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <bits/pthreadtypes.h>
static pthread_rwlock_t rwlock;//读写锁对象
#define WORK_SIZE 1024
char work_area[WORK_SIZE];//共享全局数据
int time_to_exit;//退出标识符
void *thread_function_read_o(void *arg);//读线程1
void *thread_function_read_t(void *arg);//读线程2
void *thread_function_write_o(void *arg);//写线程1
void *thread_function_write_t(void *arg);//写线程2
int main(int argc,char *argv[])
{
int res;
pthread_t a_thread,b_thread,c_thread,d_thread;
void *thread_result;
/*补充代码①,初始化读写锁*/
if (res != 0)
{
perror("rwlock initialization failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&a_thread, NULL, thread_function_read_o, NULL);//创建线程a_thread
if (res != 0)
{
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&b_thread, NULL, thread_function_read_t, NULL);//创建线程b_thread
if (res != 0)
{
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&c_thread, NULL, thread_function_write_o, NULL);//创建线程c_thread
if (res != 0)
{
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&d_thread, NULL, thread_function_write_t, NULL);//创建线程d_thread
if (res != 0)
{
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
res = pthread_join(a_thread, &thread_result);//等待a_thread线程结束
if (res != 0)
{
perror("Thread join failed");
exit(EXIT_FAILURE);
}
res = pthread_join(b_thread, &thread_result);//等待b_thread线程结束
if (res != 0)
{
perror("Thread join failed");
exit(EXIT_FAILURE);
}
res = pthread_join(c_thread, &thread_result);//等待c_thread线程结束
if (res != 0)
{
perror("Thread join failed");
exit(EXIT_FAILURE);
}
res = pthread_join(d_thread, &thread_result);//等待d_thread线程结束
if (res != 0)
{
perror("Thread join failed");
exit(EXIT_FAILURE);
}
/*补充代码②,销毁读写锁*/
exit(EXIT_SUCCESS);
}
void *thread_function_read_o(void *arg)//读线程1
{
printf("thread read one try to get lock\n");
/*补充代码③,获取读锁*/
while(strncmp("end", work_area, 3) != 0) //比较是否为结束描述符
{
printf("this is thread read one.");
printf("the characters is %s",work_area);//输出
pthread_rwlock_unlock(&rwlock);//解锁
sleep(2);
pthread_rwlock_rdlock(&rwlock);//获取读锁
while (work_area[0] == '\0' )
{
pthread_rwlock_unlock(&rwlock);//解锁
sleep(2);
pthread_rwlock_rdlock(&rwlock);//获取读锁
}
}
pthread_rwlock_unlock(&rwlock);//解锁
time_to_exit=1;
pthread_exit(0);
}
void *thread_function_read_t(void *arg)//读线程2
{
printf("thread read one try to get lock\n");//获取读锁
/*补充代码③,获取读锁*/
while(strncmp("end", work_area, 3) != 0)
{
printf("this is thread read two.");
printf("the characters is %s",work_area);
pthread_rwlock_unlock(&rwlock);//解锁
sleep(5);
pthread_rwlock_rdlock(&rwlock);//获取读锁
while (work_area[0] == '\0' )
{
pthread_rwlock_unlock(&rwlock);//解锁
sleep(5);
pthread_rwlock_rdlock(&rwlock);//获取读锁
}
}
pthread_rwlock_unlock(&rwlock); //解锁
time_to_exit=1;
pthread_exit(0);
}
void *thread_function_write_o(void *arg)//写线程1
{
printf("this is write thread one try to get lock\n");
while(!time_to_exit)
{
pthread_rwlock_wrlock(&rwlock);//获取写锁
printf("this is write thread one.\nInput some text. Enter 'end' to finish\n");
/*补充代码④,读取标准输入流,并存储*/
pthread_rwlock_unlock(&rwlock);//解锁
sleep(15);
}
pthread_rwlock_unlock(&rwlock);//解锁
pthread_exit(0);
}
void *thread_function_write_t(void *arg)//写线程2
{
sleep(10);
while(!time_to_exit)
{
pthread_rwlock_wrlock(&rwlock);//获取写锁
printf("this is write thread two.\nInput some text. Enter 'end' to finish\n");
/*补充代码④,读取标准输入流,并存储*/
pthread_rwlock_unlock(&rwlock);//解锁
sleep(20);
}
pthread_rwlock_unlock(&rwlock);//解锁
pthread_exit(0);
}
1.1补充代码①,初始化读写锁
-
A.res=pthread_create(&rwlock,NULL);
-
B.res=pthread_rwlock_init(&rwlock,NULL);
read-write lock initialize : 读写锁初始化
-
C.res=pthread_cond_init(&rwlock,NULL);
-
D.res=pthread_rwlock_create(&rwlock,NULL);
1.2补充代码②,销毁读写锁
-
A.pthread_rwlock_join(&rwlock);
-
B.pthread_cond_destroy(&rwlock);
-
C.pthread_destroy(&rwlock);
-
D.pthread_rwlock_destroy(&rwlock);
read-write lock destroy : 读写锁摧毁
1.3补充代码③,获取读锁代码
-
A.pthread_rwlock_wrlock(&rwlock);
-
B.pthread_rwlock_rdlock(&rwlock);
rwlock_rdlock : 读写锁-读锁
-
C.pthread_rdlock_wrlock(&rwlock);
-
D.pthread_rdlock_rwlock(&rwlock);
1.4补充代码④,读取标准输入流,并存储
-
A.fgets(work_area, WORK_SIZE, stdin);
-
B.fgets( WORK_SIZE,work_area, stdin);
-
C.fgets(work_area, WORK_SIZE, stdout);
-
D.fgets(WORK_SIZE,work_area,stdout);
2、生产消费
2.1补全代码①接收端和发送端可分别通过什么命令创建或读取信号量?
A.发送端: if((semid=semget((key_t)123456,1,0666|IPC_CREAT))==-1)
√ 接收端: if((semid=semget((key_t)123456,1,0666|IPC_CREAT))==-1)
B.发送端: if((semid=semget((key_t)123456,1,0666|IPC_CREAT))==-1)
接收端: if((semid=semget((key_t)654321,1,0666|IPC_CREAT))==-1)
C.发送端: if((semid=semget((key_t)123456,1,0666|IPC_CREAT))==-1)
接收端: if((semid=semget((key_t)123456,1,0666|IPC_NOWAIT))==-1)
D.发送端: if((semid=semget((key_t)123456,1,0666|IPC_CREAT))==-1)
接收端: if((semid=semget((key_t)123456,1,0666|IPC_NOWAIT))==-1)
解释如下:
key_t
是信号量的键值,用于标识信号量集。1
表示信号量集中的信号量数量。0666
是权限标志,表示读写权限。IPC_CREAT
标志表示如果信号量集不存在则创建它。发送端和接收端都使用相同的键值
(key_t)123456
和相同的标志0666 | IPC_CREAT
,这样它们就能访问到同一个信号量集。
2.2补全代码②接收端和发送端可分别通过什么命令创建或读取共享内存?
A.发送端: shid=shmget((key_t)123456,(size_t)2048,0600|IPC_CREAT);
接收端: shmid=shmget((key_t)654321,(size_t)2048,0600|IPC_CREAT);
B.发送端: shid=shmget((key_t)654321,(size_t)2048,0600|IPC_CREAT);
√ 接收端: shmid=shmget((key_t)654321,(size_t)2048,0600|IPC_CREAT);
C.发送端: shid=shmget((key_t)654321,(size_t)2048,0666|IPC_CREAT);
接收端: shmid=shmget((key_t)654321,
D.发送端: shid=shmget((key_t)654321,(size_t)2048,0600|IPC_CREAT);
接收端: shmid=shmget((key_t)654321,1,0600|IPC_CREAT);
解释如下:
key_t
是共享内存的键值,用于标识共享内存段。(size_t)2048
表示共享内存段的大小。0600
是权限标志,表示读写权限。IPC_CREAT
标志表示如果共享内存段不存在则创建它。发送端和接收端都使用相同的键值
(key_t)654321
和相同的标志0600 | IPC_CREAT
,这样它们就能访问到同一个共享内存段。
2.3补全代码③接收端和发送端可分别通过什么命令将共享内存挂载到进程中?
A.发送端: shm_p=shmat(shmid,NULL,0);
接收端: sharem=shmat(shid,NULL,0);
B.发送端: sharem=shmat(shid,NULL,SHM_RND);
接收端: shm_p=shmat(shmid,NULL,SHM_EXEC);
C.发送端: sharem=shmat(shid,NULL,SHM_REMAP);
接收端: shm_p=shmat(shmid,NULL,SHM_RDONLY);
D.发送端: sharem=shmat(shid,NULL,0);
√ 接收端: shm_p=shmat(shmid,NULL,0);
解释如下:
shmid
是共享内存的标识符,用于标识共享内存段。NULL
表示让系统自动选择附加点。0
表示没有特殊标志。发送端和接收端都使用相同的共享内存标识符
shid
和shmid
,以及相同的标志0
,这样它们就能正确地附加到同一个共享内存段。
2.4下列哪段代码用途是将共享内存与进程卸载?
-
shmdt(shm_p);
用于将共享内存段从当前进程的地址空间中分离。 -
semctl(semid,0,IPC_RMID,0);
用于删除信号量集。 -
shmctl(shmid,IPC_RMID,0)
用于删除共享内存段。 -
strcmp(shm_p,"end")
用于比较两个字符串,不涉及共享内存的操作。
3、临界资源
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
void *thread_function(void *arg);
pthread_mutex_t work_mutex;//全局互斥锁对象
#define WORK_SIZE 1024
char work_area[WORK_SIZE];//全局共享数据区
int time_to_exit = 0;
int main(int argc,char *argv[])
{
int res;
pthread_t a_thread;
void *thread_result;
res = pthread_mutex_init(&work_mutex, NULL); //初始化互斥锁
if (res != 0)
{
perror("Mutex initialization failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&a_thread, NULL, thread_function, NULL);//创建新线程
if (res != 0)
{
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
/*补全代码①接收输入前,给互斥锁上锁*/
printf("Input some text. Enter 'end' to finish\n");
while(!time_to_exit) //time_to_exit由另一个线程修改
{
/*补全代码②从标准输入流读取一行信息*/
pthread_mutex_unlock(&work_mutex); //解锁,两个线程抢占互斥锁
while(1)
{
pthread_mutex_lock(&work_mutex); //上锁
if (work_area[0] != '\0') //检查读入的内存输出没有
{//输出线程将信息输出后将设置work_area[0]!='\0'
pthread_mutex_unlock(&work_mutex); //没有输出,解锁
sleep(1);
}
else //没有输出,执行下一轮读入
{
break;
}
}
}
pthread_mutex_unlock(&work_mutex);//解锁
printf("\nWaiting for thread to finish...\n");
/*补全代码③等待另一个线程a_thread结束*/
if (res != 0)
{
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joined\n");
/*补全代码④,销毁互斥锁*/
exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) //子线程执行程序
{
sleep(1);
pthread_mutex_lock(&work_mutex);//上锁,抢占资源
while(strncmp("end", work_area, 3) != 0) //判断是否为结束信息end
{
printf("You input %d characters\n", strlen(work_area) -1);//输出输入的字符个数
printf("the characters is %s",work_area);//输出输入的字符内容
work_area[0] = '\0';//最后设置第一位为'\0',标识内容已输出
pthread_mutex_unlock(&work_mutex);//解锁
sleep(1);
pthread_mutex_lock(&work_mutex);//上锁
while (work_area[0] == '\0' ) //判断第1位是否为'\0'
{//如果为'\0',表示主线程还没有输入数据
//如果不为'\0',表示有数据,执行下一轮输出操作
pthread_mutex_unlock(&work_mutex);//解锁,等待
sleep(1);
pthread_mutex_lock(&work_mutex);//上锁,再次返回判断
}
}
/*补全代码⑤,置结束标识符,通知主线程操作结束*/
work_area[0] = '\0';
pthread_mutex_unlock(&work_mutex);//解锁
pthread_exit(0);//退出
}
3.1补全代码①接收端和发送端可分别通过什么命令创建或读取信号量
-
pthread_mutex_lock
用于锁定互斥锁,以确保对共享资源的独占访问。 -
pthread_mutex_unlock
用于解锁互斥锁,以释放对共享资源的独占访问。 -
pthread_rwlock
不是有效的POSIX线程函数。 -
pthread_lock
也不是有效的POSIX线程函数。
3.2补全代码②从标准输入流读取一行信息
-
A.
fget(work_area, WORK_SIZE, stdin);
-
B.
fgets(work_area, WORK_SIZE, stderr);
-
C.
fgets(work_area, WORK_SIZE, stdout);
-
D.
fgets(work_area, WORK_SIZE, stdin);
解释如下:
fgets
用于从指定的输入流读取一行数据并存储到缓冲区中。work_area
是存储读取数据的缓冲区。WORK_SIZE
是缓冲区的大小。stdin
是标准输入流。
3.3补全代码③等待另一个线程a_thread结束
-
A.
res = pthread_creat(a_thread, &thread_result);
-
B.
res = pthread_join(a_thread, &thread_result);
-
C.
res = pthread_destroy(a_thread, &thread_result);
-
D.
res = pthread_join(b_thread, &thread_result);
解释如下:
pthread_join
用于等待指定的线程结束,并获取该线程的返回值。a_thread
是要等待的线程标识符。&thread_result
是用于存储线程返回值的指针。
3.4补全代码④,销毁互斥锁
-
A.
pthread_mutex_destroy(&work_mutex);
-
B.
pthread_mutex_lock(&work_mutex);
-
C.
pthread_mutex_unlock(&work_mutex);
-
D.
pthread_mutex_join(&work_mutex);
3.5补全代码⑤,置结束标识符,通知主线程操作结束
-
A.
time_to_exit = 0
-
B.
time_to_exit = 1
-
C.
res=0
-
D.
res=1
解释如下:
time_to_exit
是一个共享变量,用于指示操作是否应该结束。- 将
time_to_exit
设置为1
表示通知主线程或其他等待的线程操作已经结束。
4、循环链表
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "pthread.h"
#define BUFFER_SIZE 2//空间大小
struct prodcons //条件信息结构体
{
int buffer[BUFFER_SIZE]; //生产产品值
pthread_mutex_t lock; //互斥锁
int readpos, writepos; //读写位置
pthread_cond_t notempty; //条件变量,表示非空
pthread_cond_t notfull; //条件变量,表示非满
};
/*初始化仓库缓冲区 */
void init(struct prodcons *prod)//初始化
{
pthread_mutex_init(&prod->lock,NULL);//初始化互斥锁
pthread_cond_init(&prod->notempty,NULL);//初始化条件变量
pthread_cond_init(&prod->notfull,NULL);//初始化条件变量
prod->readpos = 0;//初始化读操作位置
prod->writepos = 0;//初始化写操作位置
}
void put(struct prodcons * prod, int data)//输入产品子函数
{
pthread_mutex_lock(&prod->lock);//锁定互斥锁
/*补全代码①,判断当前测试空间是否已满*/
{
printf("producer wait for not full\n");
pthread_cond_wait(&prod->notfull, &prod->lock);//等待有空间可写
}
prod->buffer[prod->writepos] = data;//写数据
prod->writepos++;//写位置加1
if (prod->writepos >= BUFFER_SIZE)//写到尾部,返回
prod->writepos = 0;
/*补全代码②,发送有数据信号*/
pthread_mutex_unlock(&prod->lock);//解锁
}
int get(struct prodcons *prod)
{
int data;
pthread_mutex_lock(&prod->lock);//锁互斥锁
/*补全代码③,测试空间内是否有数据*/
{
printf("consumer wait for not empty\n");
pthread_cond_wait(&prod->notempty, &prod->lock);//如果为空,等待
}
/*补全代码④读数据,并将读指针加1*/
if (prod->readpos >= BUFFER_SIZE) //如果读到尾部,返回
prod->readpos = 0;
/*补全代码⑤,发送空间内还有空间的信号*/
pthread_mutex_unlock(&prod->lock);//解锁
return data;
}
#define OVER (-1)
struct prodcons buffer;
/*--------------------------------------------------------*/
void * producer(void * data)//生产者
{
int n;
for (n = 0; n < 5; n++) //生产前5个产品
{
printf("producer sleep 1 second......\n");//每1秒生产一个产品
sleep(1);
printf("put the %d product\n", n);
put(&buffer, n);
}
for(n=5; n<10; n++)//生产后五个产品
{
printf("producer sleep 3 second......\n");//每3秒生产一个产品
sleep(3);
printf("put the %d product\n",n);
put(&buffer,n);
}
put(&buffer, OVER);
printf("producer stopped!\n");
return NULL;
}
/*--------------------------------------------------------*/
void * consumer(void * data)//消费者
{
int d=0;
while (1)
{
printf("consumer sleep 2 second......\n");//每2秒消费一个产品
sleep(2);
d=get(&buffer);
printf("get the %d product\n", d);
// d = get(&buffer);
if (d == OVER ) break;
}
printf("consumer stopped!\n");
return NULL;
}
/*--------------------------------------------------------*/
int main(int argc,char *argv[])
{
pthread_t th_a, th_b;
void * retval;
init(&buffer);
pthread_create(&th_a, NULL, producer, 0);//创建生产线程
pthread_create(&th_b, NULL, consumer, 0);//创建消费线程
pthread_join(th_a, &retval);//等待生产线程结束
pthread_join(th_b, &retval);//等待消费线程结束
return 0;
}
4.1补全代码①,判断当前空间是否已满
-
A.while ((prod->writepos) % BUFFER_SIZE == prod->readpos);
-
B.while ((prod->readpos + 1) == prod->readpos);
-
C.while ((prod->writepos + 1) % BUFFER_SIZE == prod->readpos);
-
D.while ((prod->readpos + 1) % BUFFER_SIZE == prod->readpos);
解释如下:
prod->writepos
是写指针的位置。prod->readpos
是读指针的位置。BUFFER_SIZE
是缓冲区的大小。(prod->writepos + 1) % BUFFER_SIZE
计算下一个写位置,如果这个位置等于prod->readpos
,则表示缓冲区已满。
4.2补全代码②,请发送有数据信号。
-
A.pthread_cond_signal(&prod->notempty);
-
B.pthread_signal(&prod->notempty);
-
C.pthread_cond_signal(&prod->notefull);
-
D.pthread_cond_signal(notempty);
解释如下:
pthread_cond_signal
用于唤醒等待指定条件变量的线程。&prod->notempty
是指向条件变量的指针,该条件变量用于表示缓冲区中有数据。
4.3补全代码③,测试空间内是否有数据
-
A.while (writepos == readpos);
-
B.while (prod->notempty == prod->notfull);
-
C.while (prod->writepos == prod->readpos);
-
D.while (notfulll==1);
解释如下:
prod->writepos
是写指针的位置。prod->readpos
是读指针的位置。- 如果
prod->writepos
等于prod->readpos
,则表示缓冲区为空,没有数据可供消费。
4.4补全代码④,读取数据,并将读指针加1.
-
A.data = prod->buffer[prod->writepos]; prod->readpos++;
-
B.data = prod->buffer[prod->readpos]; readpos++;
-
C.data = prod->buffer[prod->readpos]; prod->readpos++;
-
D.data = prod->writepos; prod->readpos++;
解释如下:
prod->buffer[prod->readpos]
表示从缓冲区的当前读位置读取数据。prod->readpos++
将读指针向前移动一个位置,以便下次读取时指向下一个数据。
4.5补全代码⑤,发送空间内还有空间的信号
-
A.pthread_cond_signal(&prod->notfull);
-
B.pthread_cond_signal(&prod->notempty);
-
C.pthread_cond_signal(notfull);
-
D.pthread_cond_signal(notempty);
解释如下:
pthread_cond_signal
用于唤醒等待指定条件变量的线程。&prod->notfull
是指向条件变量的指针,该条件变量用于表示缓冲区中还有空间。