系统调用相关函数.docx

上传人:b****6 文档编号:7298948 上传时间:2023-01-22 格式:DOCX 页数:19 大小:30.21KB
下载 相关 举报
系统调用相关函数.docx_第1页
第1页 / 共19页
系统调用相关函数.docx_第2页
第2页 / 共19页
系统调用相关函数.docx_第3页
第3页 / 共19页
系统调用相关函数.docx_第4页
第4页 / 共19页
系统调用相关函数.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

系统调用相关函数.docx

《系统调用相关函数.docx》由会员分享,可在线阅读,更多相关《系统调用相关函数.docx(19页珍藏版)》请在冰豆网上搜索。

系统调用相关函数.docx

系统调用相关函数

窗体顶端

索引:

1.fork、exec和exit对IPC对象的影响

2.fcntl记录锁

3.管道和FIFO的属性

4.管道和FIFO的限制

5.pipe函数

6.popen和pclose

7.mkfifo函数

8.SystemVIPC共性描述

9.msqid_ds结构

10.msgget函数

11.msgsnd函数

12.msgrcv函数

13.msgctl函数

14.在SystemV消息队列上使用select和poll

15.semid_ds结构

16.semget函数

17.semop函数

18.semctl函数

19.shmid_ds结构

20.shmget函数

21.shmat函数

22.shmdt函数

23.shmctl函数

24.mmap函数

25.munmap函数

26.msync函数

27.匿名内存映射

 

1.fork、exec和exit对IPC对象的影响

IPC类型

fork

exec

_exit

 

 

 

 

管道和FIFO

子进程取得父进程的所有打开着的描述字的拷贝

所有打开的描述字继续打开着,除非已设置描述字的FD_CLOEXEC位

关闭所有打开着的描述字,最后一个关闭时删除管道或FIFO中残留的所有数据

Posix消息队列

子进程取得父进程的所有打开着的消息队列描述字的拷贝

关闭所有打开着的消息队列描述字

关闭所有打开着的消息队列描述字

SystemV消息队列

没有效果

没有效果

没有效果

Posix互斥锁、条件变量、读写锁、基于内存的信号灯

若驻留在共享内存中而且具有进程间共享属性,则共享

除非在继续打开着的共享内存中而且具有进程间共享属性,否则消失

除非在继续打开着的共享内存中而且具有进程间共享属性,否则消失

Posix有名信号灯

父进程中所有打开着的有名信号灯在子进程中继续打开着

关闭所有打开着的有名信号灯

关闭所有打开着的有名信号灯

SystemV信号灯

子进程中所有semadj值都置为0

所有semadj值都携入新程序中

所有semadj值都加到相应的信号灯上

fcntl记录上锁

子进程不继承父进程持有的锁

只要描述字继续打开着,锁就不变

解开由进程持有的所有未处理的锁

mmap内存映射和Posix共享内存区

父进程中的内存映射存留到子进程中

去除内存映射

去除内存映射

SystemV共享内存区

附接着的共享内存区在子进程中继续附接着

断开所有附接着的共享内存区

断开所有附接着的共享内存区

子进程取得父进程的所有打开着的描述字,但是客户在门描述字上激活其过程时,只有父进程是服务器

所有门描述字都应关闭,因为它们创建时设置了FD_CLOEXEC位

关闭所有打开着的描述字

 

2.fcntl记录锁

Unix内核没有文件内记录的概念,这里的记录是指字节范围(byterange)。

Posix记录上锁定义了一个特殊的字节范围以指定整个文件,它的其始偏移为0(文件的开头),长度为0。

文件上锁是记录上锁的一个特例。

粒度(granularity)用于标记能被锁住的对象的大小。

对于Posix记录上锁来说,粒度就是单个字节。

记录上锁的Posix接口是fcntl函数:

#include

intfcntl(intfd,intcmd,…/*structflock*arg*/);

返回:

成功时取决于cmd,出错时为-1。

对应记录上锁的第三个参数arg是指向某个flock结构的指针:

structflock{

    shortl_type;/*F_RDLCK,F_WRLCK,F_UNLCK*/

    shortl_whence;/*SEEK_SET,SEEK_CUR,SEEK_END*/

    off_tl_start;/*relativestartingoffsetinbytes*/

    off_tl_len;/*#bytes;0meansuntilend-of-file*/

    pid_tpid;/*PIDreturnedbyF_GETLK*/

};

cmd命令有三个:

∙        F_SETLK:

获取(l_type为F_RDLCK或F_WRLCK)或释放(l_type为F_UNLCK)由arg指向的flock结构所描述的锁。

如果该锁无法授予调用进程,该函数就立即返回一个EACCES或EAGAIN错误而不阻塞。

∙        F_SETLKW:

该命令与上一命令相似,不同在于,若所请求的锁无法授予,则调用进程将阻塞到该锁能够授予为止。

(W的意思是“等待”)

∙        F_GETLK:

检查由arg指向的锁以确定是否有某个已存在的锁会妨碍新锁授予调用进程。

如果当前没有这样的锁存在,由arg指向的flock结构的l_type被置为F_UNLCK。

否则,关于这个已存在锁的信息将在由arg指向的flock结构中返回(该结构的内容由fcntl函数覆写),其中包含持有该锁的进程ID。

l_whence成员有三个值:

∙        SEEK_SET:

l_start相对于文件的开头解释;

∙        SEEK_CUR:

l_start相对与文件的当前字节偏移解释;

∙        SEEK_END:

l_start相对于文件的末尾解释。

l_len成员指定从该偏移开始的连续字节数。

长度为0表示锁住整个文件,一般锁整个文件如下使用:

指定l_whence成员为SEEK_SET,l_start为0,l_len为0。

fcntl记录上锁既可用于读也可用于写,对于一个文件的任意字节,最多只能存在一种类型的锁(读出锁或写入锁)。

而且,一个给定字节可以有多个读出锁,但只能有一个写入锁。

当一个描述字不是打开来用于读时,如果我们对它请求一个读出锁,错误就会发生;同样,当一个描述字不是打开来用于写时,请求一个写锁错误也会发生。

对于一个打开着某个文件的给定进程来说,当它关闭该文件的任何一个描述字或终止时,与该文件关联的所有锁都被删除。

锁不能通过fork由子进程继承。

删除锁的关键是进程ID,而不是引用同一文件的描述字数目及打开目的。

记录上锁不应该同标准I/O函数库一块使用,因为该函数库会执行内部缓冲。

当某个文件需要上锁时,为避免问题,应对它使用read和write。

使用fcntl上锁和解锁的例子见unpv22e:

lock/lockfcntl.c。

 

劝告性锁和强制性锁

Posix记录上锁是劝告性锁(advisorylocking)。

劝告性锁对协作进程(cooperatingprocesses)是足够了。

有些系统提供了强制性锁(mandatorylocking)。

使用强制性锁后,内核将检查每个read和write请求,以验证其操作不会干扰由某个进程持有的某个锁。

对于通常的阻塞式描述字,与某个强制性锁冲突的read或write将把调用进程投入睡眠,直到该锁释放为止。

对于非阻塞式描述字,与某个强制性锁冲突的read或write将导致它们返回一个EAGAIN错误。

对某个特定文件施行强制性锁,应满足:

∙        组成员执行位必须关闭;

∙        SGID位必须打开。

强制性锁不需要新的系统调用。

虽然强制性上锁有一定作用,但多个进程在更新同一个文件时,仍然会导致混乱。

进程之间还是需要某种上锁形式的协作。

当一个文件区被锁住时,待处理的读出者和写入者的优先级是不可知的。

3.管道和FIFO的属性

非阻塞方式对管道和FIFO的影响(设置方式:

open时指定O_NONBLOCK;或使用fcntl使能O_NONBLOCK标志):

当前操作

管道或FIFO的现有打开操作

阻塞(缺省)时返回

O_NONBLOCK时返回

openFIFO只读

FIFO打开来写

成功返回

成功返回

FIFO不是打开来写

阻塞到FIFO打开来写为止

成功返回

openFIFO只写

FIFO打开来读

成功返回

成功返回

FIFO不是打开来读

阻塞到FIFO打开来读为止

返回ENXIO错误

从空管道或空FIFOread

管道或FIFO打开来写

阻塞到管道或FIFO中有数据或管道或FIFO不再为写打开为止

返回EAGAIN错误

管道或FIFO不是打开来写

read返回0(文件结束符)

read返回0(文件结束符)

往管道或FIFOwrite

管道或FIFO打开来读

(见如下说明)

(见如下说明)

管道或FIFO不是打开来读

给线程产生SIGPIPE

给线程产生SIGPIPE

其他规则:

如果请求读出的数据量多于管道或FIFO中当前可用数据量,那么只返回这些可用的数据。

如果请求写入的数据的字节数小于或等于PIPE_BUF(一个Posix限制值),那么write操作保证是原子的。

O_NONBLOCK标志的设置对于write操作的原子性没有影响。

然而当一个管道或FIFO设置成非阻塞时,来自write的返回值取决于待写的字节数以及该管道或FIFO中当前可用空间的大小。

如果待写的字节数小于等于PIPE_BUF:

(1)如果该管道或FIFO中有足以存放所请求字节数的空间,那么所有数据字节都写入;

(2)如果该管道或FIFO中没有足以存放所请求字节数的空间,那么立即返回一个EAGAIN错误。

如果待写的字节数大于PIPE_BUF:

(1)如果该管道或FIFO中至少有1字节空间,那么内核写入该管道或FIFO能容纳数目的数据字节,该数目同时作为来自write的返回值;

(2)如果该管道或FIFO已满,那么立即返回一个EAGAIN错误。

如果写入一个没有打开着用于读的管道或FIFO,那么内核将产生一个SIGPIPE信号。

该信号的缺省动作是终止进程。

如果调用进程忽略了该信号,或捕获了该信号并从其信号处理程序中返回,那么write返回一个EPIPE错误。

处理SIGPIPE信号的最容易方法是忽略它,让write返回EPIPE错误,应用应该检查write的返回值。

注意:

使用管道的程序,一定要为SIGPIPE信号做好准备。

4.管道和FIFO的限制

系统加于管道和FIFO的唯一限制是:

∙        OPEN_MAX:

一个进程在任意时刻打开的最大描述字数。

∙        PIPE_BUF:

可原子的写往一个管道或FIFO的最大数据量。

OPEN_MAX的值可通过sysconf函数查询。

PIPE_BUF的值通常定义在中,但也可在运行时通过调用pathconf或fpathconf取得。

尽管针对管道的PIPE_BUF能够修改,但具体依赖于路径名所存放的底层文件系统,实际应该很少这么做。

5.pipe函数

#include

intpipe(intfd[2]);

返回:

成功时为0,出错时为-1。

创建一个管道,函数返回两个描述字:

fd[0]和fd[1],前者打开来读,后者打开来写。

宏S_ISFIFO可用于确定一个描述字或文件是否或是管道,或是FIFO。

它的唯一参数是stat结构的st_mode成员,计算结果或为真(非零),或者为假(0)。

管道是通过内核运作的,使用管道传输的每个字节的数据都穿越了用户-内核接口两次:

一次是在写入管道时,一次是在从管道读出时。

注意:

对管道的read只要该管道中存在一些数据就会马上返回;它不必等待达到所请求的字节数。

6.popen和pclose

#include

FILE*popen(constchar*command,constchar*type);

返回:

成功时为文件指针,出错时为NULL。

intpclose(FILE*stream);

返回:

成功时为shell的终止状态,出错时为-1。

popen函数创建一个管道并启动另一个进程,该进程或者从该管道读出标准输入,或者往该管道写入标准输出。

其中command是一个shell命令行,它由sh程序处理。

popen在调用进程和所指定的命令之间创建一个管道,由popen返回的值是一个标准I/OFILE指针,该指针或者用于输入,或者用于输出,具体取决于字符串type:

∙        如果type为r,那么调用进程读进command的标准输出。

∙        如果type为w,那么调用进程写到command的标准输入。

pclose函数关闭由popen创建的标准I/O流stream,等待其中的命令终止,然后返回shell的终止状态。

7.mkfifo函数

#include>

#include

intmkfifo(constchar*pathname,mode_tmode);

返回:

成功是为0,出错时为-1。

FIFO类似于管道,它是一个单向(半双工)数据流,每个FIFO有一个路径名与之关联,从而允许无亲缘关系的进程访问同一个FIFO,也称为有名管道(namedpipe)。

FIFO由mkfifo创建。

其中pahtname是一个普通的UNIX路径名,它是该FIFO的名字,mode参数指定文件权限位,类似于open的第三个参数。

mkfifo已经隐含指定O_CREAT|O_EXCL,即要么创建一个新的FIFO,要么返回一个EEXIST错误。

一个FIFO创建完毕后,它必须或者打开来读,或者打开来写,它不能打开来既读又写,因为它是半双工的。

对管道或FIFO的write总是往末尾添加数据,对它们的read总是从开头返回数据。

如果对管道或FIFO调用lseek,将返回ESPIPE错误。

打开FIFO进行处理有时序上的问题。

如果当前没有任何进程打开某个FIFO来写,那么打开该FIFO来读的进程将阻塞。

所以在多进程操作FIFO时要防止死琐的产生。

8.SystemVIPC共性描述

SystemVIPC指以下三种类型的IPC:

∙        SystemV消息队列

∙        SystemV信号灯

∙        SystemV共享内存区

所有SystemVIPC函数列表:

 

消息队列

信号灯

共享内存区

头文件

sys/msg.h

sys/sem.h

sys/shm.h

创建或打开函数

msgget

semget

shmget

控制操作函数

msgctl

semctl

shmctl

操作函数

msgsnd

msgrcv

semop

shmat

shmdt

 

 

key_t键和ftok函数

SystemVIPC使用key_t值作为它们的名字。

头文件把key_t定义为一个整数,它通常是一个至少32位的整数。

这些整数通常是由ftok函数赋予的。

ftok函数把一个已存在的路径名和一个整数标识符转换成一个key_t值,称为IPC键(IPCkey):

#include

key_tftok(constchar*pahtname,intid);

返回:

成功时为IPC键,出错时为-1。

如果pathname不存在,或者对调用进程不可访问,ftok返回-1。

注意:

∙        不能保证两个不同的路径名与同一个id值的组合产生不同的键。

∙        用于产生键的pahtname不能是服务器存活期间由它反复创建并删除的文件,否则会导致ftok多次调用返回不同的值。

 

 

ipc_perm结构

内核为每个IPC对象维护一个信息结构:

structipc_perm{

    uid_tuid;/*owner'suserid*/

    gid_tgid;/*owner'sgroupid*/

    uid_tcuid;/*creator'suserid*/

    gid_tcgid;/*creator'sgroupid*/

    mode_tmode;/*accessmodes*/

    ulong_tseq;/*slotusagesequencenumber*/

    key_tkey;/*key*/

};

 

 

创建与打开IPC对象

创建或打开一个IPC对象需要一个类型为key_t的IPC键,对此键,应用有两种选择:

1.   调用ftok,给它传递pathname和id;

2.   指定IPC_PRIVATE,它保证创建一个新的、唯一的IPC对象。

创建或打开一个IPC对象函数共同的另一个参数是oflag,它指定IPC对象的读写权限位(ipc_perm结构中的mode成员),并选择是创建一个新的IPC对象还是访问一个存在的IPC对象。

选择的规则如下:

oflag标志

不存在

已存在

无特殊标志

出错,errno=ENOENT

成功,引用已存在对象

IPC_CREAT

成功,创建新对象

成功,引用已存在对象

IPC_CREAT|IPC_EXCL

成功,创建新对象

出错,errno=EEXIST

注意:

设置IPC_EXCL但不设置IPC_CREAT没有意义。

权限位的设置如下(八进制):

∙        0400:

由用户(属主)读;

∙        0200:

由用户(属主)写;

∙        0040:

由(属)组成员读;

∙        0020:

由(属)组成员写;

∙        0004:

由其他用户读;

∙        0002:

由其他用户写;

oflag由选择参数和权限参数组合而成。

ipc_perm结构的cuid和cgid成员分别设置为调用进程的有效用户ID和有效组ID,这两个成员合称为创建者ID。

ipc_perm结构的uid和gid成员也分别设置为调用进程的有效用户ID和有效组ID,这两个成员合称为属主ID。

ipc_perm结构中的seq成员是一个槽位使用情况序列号。

该变量是一个由内核为在系统中的每个潜在的IPC对象维护的计数器。

每当删除一个IPC对象时,内核就递增相应的槽位号,若溢出则循环回0。

这避免在短时间内重用IPC标识符。

9.msqid_ds结构

对于系统中的每个SystemV消息队列,内核维护一个如下的结构:

structmsqid_ds{

    structipc_permmsg_perm;/*operationpermissionstruct*/

    structmsg*msg_first;/*ptrtofirstmessageonq*/

    structmsg*msg_last;/*ptrtolastmessageonq*/

    unsignedshortmsg_cbytes;/*current#bytesonq*/

    msgqnum_tmsg_qnum;/*#ofmessagesonq*/

    msglen_tmsg_qbytes;/*max#ofbytesonq*/

    pid_tmsg_lspid;/*pidoflastmsgsnd*/

    pid_tmsg_lrpid;/*pidoflastmsgrcv*/

    time_tmsg_stime;/*lastmsgsndtime*/

    time_tmsg_rtime;/*lastmsgrcvtime*/

    time_tmsg_ctime;/*lastchangetime*/

};

10.msgget函数

#include

intmsgget(key_tkey,intoflag);

返回:

成功时为非负标识符,出错时为-1。

用于创建一个新的SystemV消息队列或访问一个已经存在的消息队列。

参数key和oflag的说明见前。

返回值是一个整数标识符,其他三个msg函数用它来指代该队列。

当创建一个消息队列时,msqid_ds结构的如下成员被初始化:

∙        msg_perm结构的uid和cuid被设置为当前进程的有效用户ID,gid和cgid被设置为当前用户的有效组ID;

∙        oflag中的读写权限位存放在msg_perm.mode中;

∙        msg_qnum、msg_lspid、msg_lrpid、msg_stime和msg_rtime被置为0;

∙        msg_ctime被设置成当前时间;

∙        msg_qbytes被设置为系统限制值。

11.msgsnd函数

#include

intmsgsnd(intmsgid,constvoid*ptr,size_tlength,intflag);

返回:

成功时为0,出错时为-1。

该函数用于往消息队列上放置一个消息。

msgid是msgget返回的标识符,ptr是一个结构指针,该结构有如下的模板:

structmsgbuf{

    longmtype;/*messagetype,mustbe>0*/

    charmtext[1];/*messagedata*/

};

消息类型mtype必须大于0,因为非正消息类型有特殊的指示作用。

length参数以字节为单位指定待发送消息的长度。

这是位于长整数消息类型之后的用户自定义数据的长度,该长度可以是0。

flag参数可以是0,也可以是IPC_NOWAIT。

IPC_NOWAIT标志使得msgsnd调用非阻塞。

当有如下情形之一时:

1.   在指定的队列中已经有太多的字节(对应msqid_ds结构中的msg_qbytes值);

2.   在系统范围存在太多的消息。

若设置了IPC_NOWAIT,则msgsnd立即返回,返回一个EAGAIN错误。

若未指定该标志,则msgsnd阻塞,直到:

1.   具备存放新消息的空间;

2.   有msgid标识的消息队列被删除,此时返回EIDRM错误;

3.   被信号中断,此时返回EINTR错误。

12.msgrcv函数

#include

ssize_tmsgrcv(intmsqid,void*ptr,size_tlength,longtype,intflag);

返回:

成功时为读入缓冲区中数据的字节数,出错时为-1。

该函数从某个消息队列中读出一个消息。

ptr参数指定所接收消息的存放位置。

跟msgsnd一样,该指针指向紧挨在真正的消息数据之前返回的长整数类型字段。

length指定由ptr指向的缓冲区中数据部分的大小。

这是该函数能返回的最大数据量。

该长度不包含长整数类型字段。

type指定希望从所给定的队列中读出什么样的消息:

1

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 政史地

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1