爱问 爱问共享资料 爱问分类
首页 > > > 系统调用相关函数.doc

系统调用相关函数.doc

系统调用相关函数.doc

上传者: 黄威
7次下载 0人收藏 暂无简介 简介 2011-06-25 举报

简介:嵌入式开发,minigui

窗体顶端索引:1.fork、exec和exit对IPC对象的影响2.fcntl记录锁3.管道和FIFO的属性4.管道和FIFO的限制5.pipe函数6.popen和pclose7.mkfifo函数8.SystemVIPC共性描述9.msqid_ds结构10.msgget函数11.msgsnd函数12.msgrcv函数13.msgctl函数14.在SystemV消息队列上使用select和poll15.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类型forkexec_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<fcntl.h>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的值通常定义在<limits.h>中,但也可在运行时通过调用pathconf或fpathconf取得。尽管针对管道的PIPE_BUF能够修改,但具体依赖于路径名所存放的底层文件系统,实际应该很少这么做。5.pipe函数#include<unistd.h>intpipe(intfd[2]);返回:成功时为0,出错时为-1。创建一个管道,函数返回两个描述字:fd[0]和fd[1],前者打开来读,后者打开来写。宏S_ISFIFO可用于确定一个描述字或文件是否或是管道,或是FIFO。它的唯一参数是stat结构的st_mode成员,计算结果或为真(非零),或者为假(0)。管道是通过内核运作的,使用管道传输的每个字节的数据都穿越了用户-内核接口两次:一次是在写入管道时,一次是在从管道读出时。注意:对管道的read只要该管道中存在一些数据就会马上返回;它不必等待达到所请求的字节数。6.popen和pclose#include<stdio.h>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<sys/types.h>>#include<sys/stat.h>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.hsys/sem.hsys/shm.h创建或打开函数msggetsemgetshmget控制操作函数msgctlsemctlshmctl操作函数msgsndmsgrcvsemopshmatshmdt  key_t键和ftok函数SystemVIPC使用key_t值作为它们的名字。头文件<sys/types.h>把key_t定义为一个整数,它通常是一个至少32位的整数。这些整数通常是由ftok函数赋予的。ftok函数把一个已存在的路径名和一个整数标识符转换成一个key_t值,称为IPC键(IPCkey):#include<sys/ipc.h>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<sys/msg.h>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<sys/msg.h>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<sys/msg.h>ssize_tmsgrcv(intmsqid,void*ptr,size_tlength,longtype,intflag);返回:成功时为读入缓冲区中数据的字节数,出错时为-1。该函数从某个消息队列中读出一个消息。ptr参数指定所接收消息的存放位置。跟msgsnd一样,该指针指向紧挨在真正的消息数据之前返回的长整数类型字段。length指定由ptr指向的缓冲区中数据部分的大小。这是该函数能返回的最大数据量。该长度不包含长整数类型字段。type指定希望从所给定的队列中读出什么样的消息:1.   type为0,返回队列中第一个消息。每个消息队列是作为一个FIFO链表维护的,所以返回的是队列中最早的消息。2.   type大于0,返回其类型值为type的第一个消息。3.   type小于0,返回其类型值小于或等于type参数的绝对值的消息中类型值最小的第一个消息。flag参数指定所请求的消息不在队列中时怎么办。在没有消息时,若设置了IPC_NOWAIT标志,则函数立即返回一个ENOMSG错误;否则,调用者阻塞知道如下某个时间发生:1.   有一个所请求类型的消息可获取;2.   由msqid标识的消息队列被删除,此时返回个EIDRM错误;3.   被某个捕获的信号中断,此时返回EINTR错误。13.msgctl函数#include<sys/msg.h>intmsgctl(intmsqid,intcmd,structmsqid_ds*buf);返回:成功时为0,出错时为-1。该函数提供在一个消息队列上的各种控制操作。msgctl提供三个命令:        IPC_RMID:从系统中删除由msqid指定的消息队列。当前在该队列上的任何消息都被丢弃。此时。第三个参数忽略不用。        IPC_SET:给指定的消息队列设置其msqid_ds结构的以下四个成员:msg_perm.uid、msg_perm.gid、msg_perm.mode和msg_perm.qbytes。它们的值来自buff指向的结构中的相应成员。        IPC_STAT:通过buff参数给调用者返回所指定消息队列中的当前msqid_ds结构。14.在SystemV消息队列上使用select和pollSystemV消息队列通过标识符而不是描述字标识,所以不能在消息队列上直接使用select和poll。解决问题的方法之一是:让服务器创建一个管道,然后派生一个子进程,由子进程阻塞在msgrcv调用中。当有消息准备好被处理时,msgrcv返回,子进程读出该消息,并把消息写入管道。服务器父进程可能在管道以及一些网络连接上select。这种办法的负面效果是消息被处理了三次,为避免此种情况,父进程可以创建一个在它自身和子进程之间分享的共享内存区,然后把管道用作父子进程见的一种标志。与网络编程相比,SystemV消息队列的另一个遗失特性是无法窥探一个消息,而这是recv、recvfrom和recvmsg函数的MSG_PEEK标志提供的能力。15.semid_ds结构SystemV信号灯是信号灯集的概念:一个或多个信号灯构成一个集合。对于系统每个信号灯集,内核维护如下的一个结构:structsemid_ds{    structipc_permsem_perm;/*operationpermissionstruct*/    structsem*sem_base;/*ptrtofirstsemaphoreinset*/    unsignedshortsem_nsems;/*#ofsemaphoresinset*/    time_tsem_otime;/*lastsemoptime*/    time_tsem_ctime;/*lastchangetime*/};当前信号灯集中的每个信号灯对应一个sem结构。定义如下:structsem{    signedshortsemval;/*semaphoretextmapaddress*/    pid_tsempid;/*pidoflastoperation*/    unsignedshortsemncnt;/*#awaitingsemval>cval*/    unsignedshortsemzcnt;/*#awaitingsemval=0*/};16.semget函数#include<sys/sem.h>intsemget(key_tkey,intnsems,intoflag);返回:成功时为非负标识符,出错时为-1。创建一个信号灯集或访问一个已存在的信号灯集。返回值是信号灯标识符,供其他信号灯函数使用。nsems是集合中的信号灯数。如果不是创建一个信号灯集,而只是访问已存在的集合,则该参数可以指定为0。一旦创建完毕一个信号灯集,就不能改变其中的信号灯数。当实际操作为创建一个新的信号灯集时,semid_ds结构的以下成员将被初始化:1.   sem_perm结构的uid和cuid被设置为调用进程的有效用户ID,gid和cgid被设置为调用进程的有效组ID;2.   oflag参数中的读写权限存入sem_perm.mode中;3.   sem_otime被设置为0,sem_ctime被置为当前时间;4.   sem_nsems被置为nsems参数的值;5.   与该集合中每个信号灯关联的各个sem结构并不初始化。这些结构必须是在以SETVAL或SETALL命令调用semctl时初始化的。SystemV信号灯的创建和初始化需两次函数调用是一个致命的缺陷,这会导致竞争状态的出现。解决竞争状态的方法是:当semget创建一个新的信号灯集时,其semid_ds结构的sem_otime成员保证被设置为0。该成员只是在semop调用成功时才被设置为当前值。在调用semget进行访问而不是创建时,以IPC_STAT命令调用semctl,然后等待sem_otime变为非零值。到时就可断定该信号灯已经被初始化,而且对它初始化的进程已成功完成semop调用。所以,创建该信号灯集的进程必须初始化它的值,而且必须在任何其他进程可以使用该信号灯集之前调用semop。例子程序见:unpv22e:lock/locksvsem.c。17.semop函数#include<sys/sem.h>intsemop(intsemid,structsembuf*opsptr,size_tnops);返回:成功时为0,出错时为-1。对一个或多个信号灯进行操作。opsptr指向如下结构模板的数组(该结构可能不止如下几个成员):structsembuf{    shrotsem_num;/*semaphorenumber:0,1,..,nsems-1*/    shortsem_op;/*semaphoreoperation:<0,0,>0*/    shortsem_flg;/*operationflags:0,IPC_NOWAIT,SEM_UNDO*/};nops参数指出结构数组中元素的个数。每个元素给目标信号灯集中某个信号灯指定一个操作。特定的信号灯由sem_num指定;sem_op指定特定的操作;sem_flg指定非阻塞(IPC_NOWAIT)、恢复等标志。在阻塞、非阻塞情况下返回的错误情况与其他SystemVIPC相同。semop函数由内核保证原子的执行,内核或者完成所有操作,或者什么也不做。semop操作的具体描述:        如果sem_op是正数,其值就加到semval(信号灯的当前值)上,这对应于释放由某个信号灯控制的资源。如果指定了SEM_UNDO标志,就从相应信号灯的semadj值中减掉sem_op的值。        如果sem_op是0,那么调用者希望等待到semval变为0,如果semval已经是0,则立即返回;如果semval不为0,相应信号灯的semzcnt(等待semval变为0的线程数)值就加1,调用线程阻塞到semval变为0(那时semzcnt再减1)。若指定了IPC_NOWAIT,则调用线程不会睡眠,返回EAGAIN。        如果sem_op是负数,那么调用者希望等待semval变为大于或等于sem_op的绝对值,这对应于分配资源。如果semval大于或等于sem_op的绝对值,则从semval中减掉sem_op的绝对值,如果指定了SEM_UNDO,那么sem_op的绝对值就加到相应信号灯的semadj值上。如果semval小于sem_op的绝对值,相应信号灯的semncnt值就加1,调用线程阻塞直到semval变为大于或等于sem_op的绝对值。若指定了IPC_NOWAIT,则调用线程不会睡眠,返回EAGAIN。semadj称为指定信号灯针对调用进程的调整值。当调用进程终止时,semadj的值就加到相应信号灯的semval上。若调用进程对某个信号灯的全部操作都指定SEM_UNDO标志,则该进程终止时,该信号灯的值就会变得像根本没有运行过该进程一样,这就是复旧(undo)的本意。18.semctl函数#include<sys/sem.h>intsemctl(intsemid,intsemnum,intcmd,…/*unionarg*/);返回:成功时为非负值,出错时为-1。对一个信号灯执行各种控制操作。semnum标识某个信号灯,semnum仅仅用于GETVAL、SETVAL、GETNCNT、GETZCNT和GETPID命令。第四个参数是可选的,它依赖于第三个参数cmd。它是一个联合:unionsemun{    intval;/*usedforSETVALonly*/    structsemid_ds*buf;/*usedfroIPC_SETandIPC_STAT*/    ushort*array;/*usedforGETALLandSETALL*/};该联合没有出现在任何系统头文件中,由应用程序声明。而且它是以值传递的,而不是以引用传递的。SystemV支持如下cmd值(除特别声明,成功时返回0,失败返回-1):        GETVAL:把semval的当前值作为函数返回值返回。        SETVAL:把semval设置为arg.val。如果操作成功,那么相应信号灯在所在进程中的调整值(semadj)将被置为0。        GETPID:把sempid的当前值作为函数值返回。        GETNCNT:把semncnt的当前值作为函数值返回。        GETZCNT:把semzcnt的当前值作为函数值返回。        GETALL:返回所指定信号灯集的每个成员的semval值。这些值通过arg.array指针返回。函数本身返回值为0。注意,调用者必须分配足够容纳所指定信号灯集中所有成员的semval值的一个unsignedshort整数数组,然后把arg.array设置成指向这个数组。        SETALL:设置所指定信号灯集中每个成员的semval值。这些值通过arg.array数组指定。        IPC_RMID:把由semid指定的信号灯集从系统中删除。        IPC_SET:设置semid_ds结构中的以下三个成员:sem_perm.uid、sem_perm.gid和sem_perm.mode。这些值来自由arg.buf参数指向的结构中相应成员。semid_ds中的sem_ctime成员也被设置为当前值。        IPC_STAT:通过arg.buf参数返回当前的semid_ds结构。注意,调用者必须首先分配一个semid_ds结构,并把arg.buf设置为指向这个结构。19.shmid_ds结构对于每个SystemV共享内存区,内核维护如下的信息结构:structshmid_ds{    structipc_permshm_perm;/*operationpermissionstruct*/    size_tshm_segsz;/*sizeofsegmentinbytes*/    pid_tshm_lpid;/*pidoflastshmop*/    pid_tshm_cpid;/*pidofcreator*/    shmatt_tshm_nattch;/*current#attached*/    shmat_tshm_cnattch;/*in-core#attached*/    time_tshm_atime;/*lastshmattime*/    time_tshm_dtime;/*lastshmdttime*/    time_tshm_ctime;/*lastchangetime*/};20.shmget函数#include<sys/shm.h>intshmget(key_tkey,size_tsize,intoflag);返回:成功时为共享内存区对象,出错时为-1。函数创建一个尚未存在的共享内存区,或者访问一个已存在的共享内存区。返回值是共享内存区标识符,供其他函数使用。size参数以字节为单位指定内存的大小。当实际操作为创建一个新的内存区时,必须指定一个不为0的size值;如果实际操作是访问一个已存在的共享内存区,则size应为0。当实际操作为创建一个新的内存区时,该内存区被初始化为size个字节的0。21.shmat函数#include<sys/shm.h>void*shmat(intshmid,constvoid*shmaddr,intflag);返回:成功时为映射区的其始地址,出错时为-1。调用shmat将共享内存区附接到调用进程的地址空间。shmid是shmget的返回值。shmat的返回值是所指定的共享内存区在调用进程内的起始地址。确定此地址的规则如下:        如果shmaddr是空指针,则系统替调用者选择地址。这是推荐(也是可移植性最好的)方法。        如果shmaddr非空,则返回地址取决于调用者是否给flag参数指定了SHM_RND值。如果SHM_RND没有指定,则共享内存区附接到由shmaddr指定的地址;若指定SHM_RND,则附接到由shmaddr指定的地址向下舍入一个SHMLBA常值。LBA代表“低端边界地址(lowerboundaryaddress)。flag参数可以指定SHM_RDONLY值,它限定只读访问。22.shmdt函数#include<sys/shm.h>intshmdt(constvoid*shmaddr);返回:成功时为0,出错时为-1。调用shmdt断开与共享内存区的连接。当一个进程终止时,它的所有当前附接着的共享内存区都自动断接掉。23.shmctl函数#include<sys/shm.h>intshmctl(intshmid,intcmd,structshmid_ds*buff);返回:成功时为0,出错时为-1。函数提供三个命令:        IPC_RMID:从系统中删除由shmid标识的共享内存区并拆除它。        IPC_SET:给所指定的共享内存区设置其shmid_ds结构的以下三个成员:shm_perm.uid、shm_perm.gid和shm_perm.mode,它们的值来自参数中的相应成员。shm_ctime的值用当前时间替换。        IPC_STAT:向调用者返回所指定共享内存区的当前shmid_ds结构。24.mmap函数#include<sys/mman.h>void*mmap(void*addr,size_tlen,intprot,intflags,intfd,off_toffset);返回:成功时为被映射区的起始地址,出错时为MAP_FAILD。mmap函数把一个文件或一个Posix共享内存区对象映射到调用进程的地址空间。使用该函数有三个目的:        使用普通文件以提供内存映射;        使用特殊文件以提供匿名内存映射;        使用shm_open以提供无亲缘关系进程间的Posix共享内存区。其中addr可以指定为描述字fd应被映射到的进程内空间的起始地址。它通常被指定为一个空指针,让内核自己去选择起始地址。Len是映射到调用进程地址空间的字节数,它从被映射文件开头起offset个字节处开始算。内存映射区的保护由prot参数指定,它使用如下的常值。该参数的常见值是PROT_READ|PROT_WRITE:        PROT_READ:数据可读;        PROT_WRITE:数据可写;        PROT_EXEC:数据可执行;        PROT_NONE:数据不可访问。flags使用如下的常值。MAP_SHARED或MAP_PRIVATE这两个标志必须指定一个,并可有选择的或上MAP_FIXED。MAP_PRIVATE的含义是调用进程对被映射数据所作的修改只对该进程可见,而不改变其底层支撑对象(或者是一个文件对象,或者是一个共享内存区对象)。MAP_SHARED的含义则是调用进程对被映射数据所作的修改对于共享该对象的所有进程都可见,而且确实改变了其底层支撑对象。从移植性上考虑,MAP_FIXED不应该指定:        MAP_SHARED:变动是共享;        MAP_PRIVATE:变动是私自的;        MAP_FIXED:准确的解释addr参数。mmap成功返回后,fd参数可以关闭。该操作对于由mmap建立的映射关系没有影响。父子进程之间共享内存区的方法之一是,父进程在调用fork前指定MAP_SHARED调用mmap。Posix.1保证父进程中的内存映射关系存留到子进程中,而且父进程所作的修改子进程能看到,反过来也一样。不是所有的文件都能进行内存映射。如把一个访问终端或套接口的描述字映射到内存将导致mmap返回一个错误。内存映射区的大小(mmap的第二个参数)可以与文件的大小不同。但是,内核跟踪着被内存映射的底层支撑对象的大小,而且我们总是能访问在当前文件大小以内又在内存映射区以内的那些字节。25.munmap函数#include<sys/mman.h>intmunmap(void*addr,size_tlen);返回:成功时为0,出错时为-1。其中addr是mmap返回的地址,len是映射区的大小。从进程地址空间删除一个映射关系。之后再次访问这些地址将导致向调用进程产生一个SIGSEGV信号。如果映射区用MAP_PRIVATE标志映射,那么调用进程对它所作的变动都被丢弃。26.msync函数#include<sys/mman.h>intmsync(void*addr,size_tlen,intflags);返回:成功时为0,出错时为-1。内核的虚存算法保持内存映射文件(一般在硬盘上)与内存映射区(在内存中)的同步(使用了MAP_SHARED),如果我们修改了内存映射到某个文件的内存区中某个位置的内容,那么内核将在稍后某个时刻相应的更新文件。如果我们希望确信硬盘上的文件内容与内存映射区中的内容一致,则调用msync来执行这种同步。其中addr和len参数通常指代内存中的整个内存映射区,不过也可指定该内存区的一个子集。flags是如下常值的组合:        MS_ASYNC:执行异步写;        MS_SYNC:执行同步写;        MS_INVALIDATE:是高速缓存的数据失效。MS_ASYNC和MS_SYNC这两个值必须指定一个,但不能都指定。两者的差别是,一旦写操作已由内核排入队列,MS_ASYNC即返回,而MS_SYNC则要等到写操作完成后返回。如果还指定了MS_INVALIDATE,那么与其最终拷贝不一致的文件数据的所有内存中拷贝都失效,后续的引用将从文件中取得数据。27.匿名内存映射如果调用mmap的目的是提供一个即将穿越fork由父子进程共享的映射内存区,则可以不用创建一个文件,在open它等一系列操作。具体依赖于实现:        4.4BSD提供匿名内存映射,它彻底避免了文件的创建和打开。方法是把mmap的flags参数指定为MAP_SHARED|MAP_ANON,把fd参数指定为-1,offset参数被忽略。这样的内存区初始化为0。        SVR4提供/dev/zero设备文件,我们open它之后可在mmap调用中使用得到的描述字。从该设备读时返回的字节全为0,写往该设备的任何字节则被丢弃。(许多源自Berkeley的实现也支持/dev/zero,如SunOs4.1.x和BSD/OS3.1)。例子见unpv22e:shm/incr_map_anon.c和shm/incr_dev_zero.c。发表于@2010年05月15日 17:36:00 |评论(0)|编辑|举报|收藏旧一篇:怎样学好C语言 | 新一篇:Linux进程间通讯之信号量专区推荐

系统调用相关函数.doc

系统调用相关函数.doc

上传者: 黄威
7次下载 0人收藏 暂无简介 简介 2011-06-25 举报

简介:嵌入式开发,minigui

索引: 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页

  • 相关资料
  • 该用户的其他资料
  • 名称/格式
  • 下载次数
  • 资料大小
  • 名称/格式
  • 下载次数
  • 资料大小

用户评论

0/200
暂无评论
上传我的资料
关闭

请选择举报的类型

关闭

提示

提交成功!

感谢您对爱问共享资料的支持,我们将尽快核实并处理您的举报信息。

关闭

提示

提交失败!

您的举报信息提交失败,请重试!

关闭

提示

重复举报!

亲爱的用户!感觉您对爱问共享资料的支持,请勿重复举报噢!

全屏 缩小 放大
收藏
资料评价:

/ 22
所需积分:5 立即下载
返回
顶部
举报
资料
关闭

温馨提示

感谢您对爱问共享资料的支持,精彩活动将尽快为您呈现,敬请期待!