⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 1037.html

📁 著名的linux英雄站点的文档打包
💻 HTML
📖 第 1 页 / 共 5 页
字号:
int change_queue_mode(int qid, char *mode )<br>
{<br>
struct msqid_ds tmpbuf;<br>
/* Retrieve a current copy of the internal data structure */<br>
get_queue_ds( qid, &tmpbuf);<br>
/* Change the permissions using an old trick */<br>
sscanf(mode, "%ho", &tmpbuf.msg_perm.mode);<br>
/* Update the internal data structure */<br>
if( msgctl( qid, IPC_SET, &tmpbuf) == -1)<br>
{<br>
return(-1);<br>
}<br>
return(<br>
}<br>
<br>
我们通过调用get_queue_ds来读取队列的内部数据结构。然后,我们调用sscanf( )修改数据结构msg_perm中的mode 成员的值。但直到调用msgctl()时,权限的改变才真正完成。在这里msgctl()使用的是IPC_SET命令。<br>
最后,我们使用系统调用msgctl ( )中的IPC_RMID命令删除消息队列:<br>
<br>
int remove_queue(int qid )<br>
{<br>
if( msgctl( qid, IPC_RMID, 0) == -1)<br>
{<br>
return(-1);<br>
}<br>
return(0);<br>
}<br>
};<br>
<br>
<br>
<br>
[目录]<br>
<br>
--------------------------------------------------------------------------------<br>
<br>
<br>
信号量<br>
<br>
信号量是一个可以用来控制多个进程存取共享资源的计数器。它经常作为一种锁定机制来防止当一个进程正在存取共享资源时,另一个进程也存取同一资源。下面先简要地介绍一下信号量中涉及到的数据结构。<br>
1.内核中的数据结构semid_ds<br>
和消息队列一样,系统内核为内核地址空间中的每一个信号量集都保存了一个内部的数据结构。数据结构的原型是semid_ds。它是在linux/sem.h中做如下定义的:<br>
/*One semid data structure for each set of semaphores in the system.*/<br>
structsemid_ds{<br>
structipc_permsem_perm;/*permissions..seeipc.h*/<br>
time_tsem_otime;/*last semop time*/<br>
time_tsem_ctime;/*last change time*/<br>
structsem*sem_base;/*ptr to first semaphore in array*/<br>
structwait_queue*eventn;<br>
structwait_queue*eventz;<br>
structsem_undo*undo;/*undo requestson this array*/<br>
ushortsem_nsems;/*no. of semaphores in array*/<br>
};<br>
sem_perm是在linux/ipc.h定义的数据结构ipc_perm的一个实例。它保存有信号量集的存取权限的信息,以及信号量集创建者的有关信息。<br>
sem_otime最后一次semop()操作的时间。<br>
sem_ctime最后一次改动此数据结构的时间。<br>
sem_base指向数组中第一个信号量的指针。<br>
sem_undo数组中没有完成的请求的个数。<br>
sem_nsems信号量集(数组)中的信号量的个数。<br>
<br>
2.内核中的数据结构sem<br>
在数据结构semid_ds中包含一个指向信号量数组的指针。此数组中的每一个元素都是一个<br>
数据结构sem。它也是在linux/sem.h中定义的:<br>
/*One semaphore structure for each semaphore in the system.*/<br>
structsem{<br>
shortsempid;/*pid of las toperation*/<br>
ushortsemval;/*current value*/<br>
ushortsemncnt;/*num procs awaiting increase in semval*/<br>
ushortsemzcnt;/*num procs awaiting semval=0*/<br>
};<br>
sem_pid最后一个操作的PID(进程ID)。<br>
sem_semval信号量的当前值。<br>
sem_semncnt等待资源的进程数目。<br>
sem_semzcnt等待资源完全空闲的进程数目。<br>
<br>
<br>
[目录]<br>
<br>
--------------------------------------------------------------------------------<br>
<br>
<br>
semget()<br>
<br>
我们可以使用系统调用semget()创建一个新的信号量集,或者存取一个已经存在的信号量集:<br>
系统调用:semget();<br>
原型:intsemget(key_t key,int nsems,int semflg);<br>
返回值:如果成功,则返回信号量集的IPC标识符。如果失败,则返回-1:errno=EACCESS(没有权限)<br>
EEXIST(信号量集已经存在,无法创建)<br>
EIDRM(信号量集已经删除)<br>
ENOENT(信号量集不存在,同时没有使用IPC_CREAT)<br>
ENOMEM(没有足够的内存创建新的信号量集)<br>
ENOSPC(超出限制)<br>
<br>
系统调用semget()的第一个参数是关键字值(一般是由系统调用ftok()返回的)。系统内核将此值和系统中存在的其他的信号量集的关键字值进行比较。打开和存取操作与参数semflg中的内容相关。IPC_CREAT如果信号量集在系统内核中不存在,则创建信号量集。IPC_EXCL当和IPC_CREAT一同使用时,如果信号量集已经存在,则调用失败。如果单独使用IPC_CREAT,则semget()要么返回新创建的信号量集的标识符,要么返回系统中已经存在的同样的关键字值的信号量的标识符。如果IPC_EXCL和IPC_CREAT一同使用,则要么返回新创建的信号量集的标识符,要么返回-1。IPC_EXCL单独使用没有意义。参数nsems指出了一个新的信号量集中应该创建的信号量的个数。信号量集中最多的信号量的个数是在linux/sem.h中定义的:<br>
<br>
#defineSEMMSL32/*&lt;=512maxnumofsemaphoresperid*/<br>
下面是一个打开和创建信号量集的程序:<br>
intopen_semaphore_set(key_t keyval,int numsems)<br>
{<br>
intsid;<br>
if(!numsems)<br>
return(-1);<br>
if((sid=semget(mykey,numsems,IPC_CREAT|0660))==-1)<br>
{<br>
return(-1);<br>
}<br>
return(sid);<br>
}<br>
};<br>
<br>
<br>
<br>
<br>
<br>
<br>
[目录]<br>
<br>
--------------------------------------------------------------------------------<br>
<br>
<br>
semop()<br>
<br>
系统调用:semop();<br>
调用原型:int semop(int semid,struct sembuf*sops,unsign ednsops);<br>
返回值:0,如果成功。-1,如果失败:errno=E2BIG(nsops大于最大的ops数目)<br>
EACCESS(权限不够)<br>
EAGAIN(使用了IPC_NOWAIT,但操作不能继续进行)<br>
EFAULT(sops指向的地址无效)<br>
EIDRM(信号量集已经删除)<br>
EINTR(当睡眠时接收到其他信号)<br>
EINVAL(信号量集不存在,或者semid无效)<br>
ENOMEM(使用了SEM_UNDO,但无足够的内存创建所需的数据结构)<br>
ERANGE(信号量值超出范围)<br>
第一个参数是关键字值。第二个参数是指向将要操作的数组的指针。第三个参数是数组中的操作的个数。参数sops指向由sembuf组成的数组。此数组是在linux/sem.h中定义的:<br>
<br>
/*semop systemcall takes an array of these*/<br>
structsembuf{<br>
ushortsem_num;/*semaphore index in array*/<br>
shortsem_op;/*semaphore operation*/<br>
shortsem_flg;/*operation flags*/<br>
sem_num将要处理的信号量的个数。<br>
sem_op要执行的操作。<br>
sem_flg操作标志。<br>
<br>
如果sem_op是负数,那么信号量将减去它的值。这和信号量控制的资源有关。如果没有使用IPC_NOWAIT,那么调用进程将进入睡眠状态,直到信号量控制的资源可以使用为止。如果sem_op是正数,则信号量加上它的值。这也就是进程释放信号量控制的资源。最后,如果sem_op是0,那么调用进程将调用sleep(),直到信号量的值为0。这在一个进程等待完全空闲的资源时使用。<br>
<br>
<br>
<br>
<br>
<br>
<br>
[目录]<br>
<br>
--------------------------------------------------------------------------------<br>
<br>
<br>
semctl()<br>
<br>
系统调用:semctl();<br>
原型:int semctl(int semid,int semnum,int cmd,union semunarg);<br>
返回值:如果成功,则为一个正数。<br>
如果失败,则为-1:errno=EACCESS(权限不够)<br>
EFAULT(arg指向的地址无效)<br>
EIDRM(信号量集已经删除)<br>
EINVAL(信号量集不存在,或者semid无效)<br>
EPERM(EUID没有cmd的权利)<br>
ERANGE(信号量值超出范围)<br>
系统调用semctl用来执行在信号量集上的控制操作。这和在消息队列中的系统调用msgctl是十分相似的。但这两个系统调用的参数略有不同。因为信号量一般是作为一个信号量集使用的,而不是一个单独的信号量。所以在信号量集的操作中,不但要知道IPC关键字值,也要知道信号量集中的具体的信号量。这两个系统调用都使用了参数cmd,它用来指出要操作的具体命令。两个系统调用中的最后一个参数也不一样。在系统调用msgctl中,最后一个参数是指向内核中使用的数据结构的指针。我们使用此数据结构来取得有关消息队列的一些信息,以及设置或者改变队列的存取权限和使用者。但在信号量中支持额外的可选的命令,这样就要求有一个更为复杂的数据结构。<br>
系统调用semctl()的第一个参数是关键字值。第二个参数是信号量数目。<br>
<br>
参数cmd中可以使用的命令如下:<br>
·IPC_STAT读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。<br>
·IPC_SET设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。<br>
·IPC_RMID将信号量集从内存中删除。<br>
·GETALL用于读取信号量集中的所有信号量的值。<br>
·GETNCNT返回正在等待资源的进程数目。<br>
·GETPID返回最后一个执行semop操作的进程的PID。<br>
·GETVAL返回信号量集中的一个单个的信号量的值。<br>
·GETZCNT返回这在等待完全空闲的资源的进程数目。<br>
·SETALL设置信号量集中的所有的信号量的值。<br>
·SETVAL设置信号量集中的一个单独的信号量的值。<br>
<br>
参数arg代表一个semun的实例。semun是在linux/sem.h中定义的:<br>
/*arg for semctl systemcalls.*/<br>
unionsemun{<br>
intval;/*value for SETVAL*/<br>
structsemid_ds*buf;/*buffer for IPC_STAT&IPC_SET*/<br>
ushort*array;/*array for GETALL&SETALL*/<br>
structseminfo*__buf;/*buffer for IPC_INFO*/<br>
void*__pad;<br>
<br>
val当执行SETVAL命令时使用。buf在IPC_STAT/IPC_SET命令中使用。代表了内核中使用的信号量的数据结构。array在使用GETALL/SETALL命令时使用的指针。<br>
下面的程序返回信号量的值。当使用GETVAL命令时,调用中的最后一个参数被忽略:<br>
<br>
intget_sem_val(intsid,intsemnum)<br>
{<br>
return(semctl(sid,semnum,GETVAL,0));<br>
}<br>
<br>
下面是一个实际应用的例子:<br>
<br>
#defineMAX_PRINTERS5<br>
printer_usage()<br>
{<br>
int x;<br>
for(x=0;x&lt;MAX_PRINTERS;x++)<br>
printf("Printer%d:%d
",x,get_sem_val(sid,x));<br>
}<br>
<br>
下面的程序可以用来初始化一个新的信号量值:<br>
<br>
void init_semaphore(int sid,int semnum,int initval)<br>
{<br>
union semunsemopts;<br>
semopts.val=initval;<br>
semctl(sid,semnum,SETVAL,semopts);<br>
}<br>
<br>
注意系统调用semctl中的最后一个参数是一个联合类型的副本,而不是一个指向联合类型的指针。<br>
<br>
<br>
<br>
<br>
[目录]<br>
<br>
--------------------------------------------------------------------------------<br>
<br>
<br>
共享内存<br>
<br>
共享内存就是由几个进程共享一段内存区域。这可以说是最快的IPC形式,因为它无须任何的中间操作(例如,管道、消息队列等)。它只是把内存段直接映射到调用进程的地址空间中。这样的内存段可以是由一个进程创建的,然后其他的进程可以读写此内存段。<br>
每个系统的共享内存段在系统内核中也保持着一个内部的数据结构shmid_ds。此数据结构是在linux/shm.h中定义的,如下所示:<br>
<br>
/* One shmid data structure for each shared memory segment in the system. */<br>
struct shmid_ds {<br>
struct ipc_perm shm_perm; /* operation perms */<br>
int shm_segsz; /* size of segment (bytes) */<br>
time_t shm_atime; /* last attach time */<br>
time_t shm_dtime; /* last detach time */<br>
time_t shm_ctime; /* last change time */<br>
unsigned short shm_cpid; /* pid of creator */<br>
unsigned short shm_lpid; /* pid of last operator */<br>
short shm_nattch; /* no. of current attaches */<br>
/* the following are private */<br>
unsigned short shm_npages; /* size of segment (pages) */<br>
unsigned long *shm_pages; /* array of ptrs to frames -&gt; SHMMAX */<br>
struct vm_area_struct *attaches; /* descriptors for attaches */<br>
};<br>
<br>
shm_perm 是数据结构ipc_perm的一个实例。这里保存的是内存段的存取权限,和其他的有关内存段创建者的信息。<br>
shm_segsz 内存段的字节大小。<br>
shm_atime 最后一个进程存取内存段的时间。<br>
shm_dtime 最后一个进程离开内存段的时间。<br>
shm_ctime 内存段最后改动的时间。<br>
shm_cpid 内存段创建进程的P I D。<br>
shm_lpid 最后一个使用内存段的进程的P I D。<br>
shm_nattch 当前使用内存段的进程总数。<br>
<br>
<br>
[目录]<br>
<br>
--------------------------------------------------------------------------------<br>
<br>
<br>
shmget()<br>
<br>
系统调用:shmget();<br>
原型:int shmget(key_t key,int size,int shmflg);<br>
返回值:如果成功,返回共享内存段标识符。如果失败,则返回-1:errno=EINVAL(无效的内存段大小)<br>
EEXIST(内存段已经存在,无法创建)<br>
EIDRM(内存段已经被删除)<br>
ENOENT(内存段不存在)<br>
EACCES(权限不够)<br>
ENOMEM(没有足够的内存来创建内存段)<br>
系统调用shmget()中的第一个参数是关键字值(它是用系统调用ftok()返回的)。其他的操作都要依据shmflg中的命令进行。<br>
·IPC_CREAT如果系统内核中没有共享的内存段,则创建一个共享的内存段。<br>
·IPC_EXCL当和IPC_CREAT一同使用时,如果共享内存段已经存在,则调用失败。<br>
当IPC_CREAT单独使用时,系统调用shmget()要么返回一个新创建的共享内存段的标识符,要么返回一个已经存在的共享内存段的关键字值。如果IPC_EXCL和IPC_CREAT一同使用,则要么系统调用新创建一个共享的内存段,要么返回一个错误值-1。IPC_EXCL单独使用没有意义。<br>
<br>
下面是一个定位和创建共享内存段的程序:<br>
<br>
int open_segment(key_t keyval,int segsize)<br>
{<br>
int shmid;<br>
if((shmid=shmget(keyval,segsize,IPC_CREAT|0660))==-1)<br>
{<br>
return(-1);<br>
}<br>
return(shmid);<br>
}<br>
<br>
一旦一个进程拥有了一个给定的内存段的有效IPC标识符,它的下一步就是将共享的内存段映射到自己的地址空间中。<br>
<br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -