zoukankan      html  css  js  c++  java
  • 16.信号量互斥编程

    16.信号量互斥编程

    我们先来看一个例子。就是两个进程访问同一个文件,由于线程的先后,导致内容的异常。即是数据内容的混乱。

    Student1.c:

    #include <unistd.h>

    #include <sys/types.h>

    #include <sys/stat.h>

    #include <fcntl.h>

    void main(){

        //open file

        int fd = 0;

        fd = open("/home/wen",O_RDWR|O_APPEND);

        //write something into file

        write(fd,"forfish!",8);

        //rest

        sleep(10);

        //write something else.

        write(fd,"is die!",7);

        close(fd);

    }

    Student2.c:

    #include <unistd.h>

    #include <sys/types.h>

    #include <sys/stat.h>

    #include <fcntl.h>

    void main(){

        int fd = 0;

        fd = open("/home/wen",O_RDWR|O_APPEND);

        write(fd,"fish!",5);

        close(fd);

    }

    运行的结果:

    最后是两个人都die了。这信息错误就严重了。所以我们要有机制来控制对资源的使用,才不会产生混乱。

    这就引出了信号量的概念:信号量(又名:信号灯)与其他进程间通信方式不大相同,主要用途是保护临界资源(进程互斥)。进程可以根据它判定是否能够访问某些共享资源。除了用于访问控制外,还可用于进程同步。

    信号量的分类:

    1. 二值信号灯:信号灯的值只能取0或1
    2. 计数信号灯:信号灯的值可以取任意非负数。

    接下来是使用信号量:

    信号量的函数:semget:

    Man 2 semget的信息:

    NAME

    semget - get a semaphore set identifier

    SYNOPSIS

    #include <sys/types.h>

    #include <sys/ipc.h>

    #include <sys/sem.h>

    int semget(key_t key, int nsems, int semflg);

    DESCRIPTION

    The semget() system call returns the semaphore set identifier associ-

    ated with the argument key. A new set of nsems semaphores is created

    if key has the value IPC_PRIVATE or if no existing semaphore set is

    associated with key and IPC_CREAT is specified in semflg.

    If semflg specifies both IPC_CREAT and IPC_EXCL and a semaphore set

    already exists for key, then semget() fails with errno set to EEXIST.

    (This is analogous to the effect of the combination O_CREAT | O_EXCL

    for open(2).)

    Upon creation, the least significant 9 bits of the argument semflg

    define the permissions (for owner, group and others) for the semaphore

    set. These bits have the same format, and the same meaning, as the

    mode argument of open(2) (though the execute permissions are not mean-

    ingful for semaphores, and write permissions mean permission to alter

    semaphore values).

    The values of the semaphores in a newly created set are indeterminate.

    (POSIX.1-2001 is explicit on this point.) Although Linux, like many

    other implementations, initializes the semaphore values to 0, a

    portable application cannot rely on this: it should explicitly initial-

    ize the semaphores to the desired values.

    When creating a new semaphore set, semget() initializes the set's asso-

    ciated data structure, semid_ds (see semctl(2)), as follows:

    sem_perm.cuid and sem_perm.uid are set to the effective user ID

    of the calling process.

    sem_perm.cgid and sem_perm.gid are set to the effective group ID

    of the calling process.

    The least significant 9 bits of sem_perm.mode are set to the

    least significant 9 bits of semflg.

    sem_nsems is set to the value of nsems.

    sem_otime is set to 0.

    sem_ctime is set to the current time.

    The argument nsems can be 0 (a don't care) when a semaphore set is not

    being created. Otherwise nsems must be greater than 0 and less than or

    equal to the maximum number of semaphores per semaphore set (SEMMSL).

    If the semaphore set already exists, the permissions are verified.

    RETURN VALUE

    If successful, the return value will be the semaphore set identifier (a

    non-negative integer), otherwise -1 is returned, with errno indicating

    the error.

    ERRORS

    On failure errno will be set to one of the following:

    EACCES A semaphore set exists for key, but the calling process does not

    have permission to access the set, and does not have the

    CAP_IPC_OWNER capability.

    EEXIST A semaphore set exists for key and semflg specified both

    IPC_CREAT and IPC_EXCL.

    EINVAL nsems is less than 0 or greater than the limit on the number of

    semaphores per semaphore set (SEMMSL), or a semaphore set corre-

    sponding to key already exists, and nsems is larger than the

    number of semaphores in that set.

    ENOENT No semaphore set exists for key and semflg did not specify

    IPC_CREAT.

    ENOMEM A semaphore set has to be created but the system does not have

    enough memory for the new data structure.

    ENOSPC A semaphore set has to be created but the system limit for the

    maximum number of semaphore sets (SEMMNI), or the system wide

    maximum number of semaphores (SEMMNS), would be exceeded.

    CONFORMING TO

    SVr4, POSIX.1-2001.

    NOTES

    IPC_PRIVATE isn't a flag field but a key_t type. If this special value

    is used for key, the system call ignores everything but the least sig-

    nificant 9 bits of semflg and creates a new semaphore set (on success).

    The following limits on semaphore set resources affect the semget()

    call:

    SEMMNI System wide maximum number of semaphore sets: policy dependent

    (on Linux, this limit can be read and modified via the fourth

    field of /proc/sys/kernel/sem).

    SEMMSL Maximum number of semaphores per semid: implementation dependent

    (on Linux, this limit can be read and modified via the first

    field of /proc/sys/kernel/sem).

    SEMMNS System wide maximum number of semaphores: policy dependent (on

    Linux, this limit can be read and modified via the second field

    of /proc/sys/kernel/sem). Values greater than SEMMSL * SEMMNI

    makes it irrelevant.

    BUGS

    The name choice IPC_PRIVATE was perhaps unfortunate, IPC_NEW would more

    clearly show its function.

    The semaphores in a set are not initialized by semget(). In order to

    initialize the semaphores, semctl(2) must be used to perform a SETVAL

    or a SETALL operation on the semaphore set. (Where multiple peers do

    not know who will be the first to initialize the set, checking for a

    non-zero sem_otime in the associated data structure retrieved by a sem-

    ctl(2) IPC_STAT operation can be used to avoid races.)

    SEE ALSO

    semctl(2), semop(2), ftok(3), capabilities(7), sem_overview(7),

    svipc(7)

    COLOPHON

    This page is part of release 3.22 of the Linux man-pages project. A

    description of the project, and information about reporting bugs, can

    be found at http://www.kernel.org/doc/man-pages/.

    创建/打开信号量集合的函数:semget:

    函数的原型:

    int semget(key_t key, int nsems, int semflg);

    函数的功能是:获取信号量集合的标示符。当key所指定的信号量不存在的时候,并且semflg里面包含了IPC_CREAT,这个时候,就会创建一个信号量集合。

    该函数要包含的头文件:

    #include <sys/types.h>

    #include <sys/ipc.h>

    #include <sys/sem.h>

    该函数的返回值:成功返回信号量集合的标示符。失败返回-1.

    参数说明:

    Key:键值。

    Semflg:标志,可以取IPC_CREAT.

    Nsems:创建的这个信号量集合里面包含的信号数目。

    键值:

    查看帮助文档:man 3 ftok:

    NAME

    ftok - convert a pathname and a project identifier to a System V IPC key

    SYNOPSIS

    #include <sys/types.h>

    #include <sys/ipc.h>

    key_t ftok(const char *pathname, int proj_id);

    DESCRIPTION

    The ftok() function uses the identity of the file named by the given pathname

    (which must refer to an existing, accessible file) and the least significant 8

    bits of proj_id (which must be non-zero) to generate a key_t type System V IPC

    key, suitable for use with msgget(2), semget(2), or shmget(2).

    The resulting value is the same for all pathnames that name the same file, when

    the same value of proj_id is used. The value returned should be different when

    the (simultaneously existing) files or the project IDs differ.

    RETURN VALUE

    On success the generated key_t value is returned. On failure -1 is returned,

    with errno indicating the error as for the stat(2) system call.

    CONFORMING TO

    POSIX.1-2001.

    NOTES

    Under libc4 and libc5 (and under SunOS 4.x) the prototype was:

    key_t ftok(char *pathname, char proj_id);

    Today proj_id is an int, but still only 8 bits are used. Typical usage has an

    ASCII character proj_id, that is why the behavior is said to be undefined when

    proj_id is zero.

    Of course no guarantee can be given that the resulting key_t is unique. Typi-

    cally, a best effort attempt combines the given proj_id byte, the lower 16 bits

    of the inode number, and the lower 8 bits of the device number into a 32-bit

    result. Collisions may easily happen, for example between files on /dev/hda1

    and files on /dev/sda1.

    SEE ALSO

    msgget(2), semget(2), shmget(2), stat(2), svipc(7)

    COLOPHON

    This page is part of release 3.22 of the Linux man-pages project. A description

    of the project, and information about reporting bugs, can be found at

    http://www.kernel.org/doc/man-pages/.

    函数的原型:

    key_t ftok(const char *pathname, int proj_id);

    该函数的功能是创建一个键值。第一个参数是信号量文件的路径,绝对路径。第二个参数是项目编号,编号不一样,键值就不一样。

    返回值就是信号量的键值。

    操作信号量

    函数semop自动执行信号量集合上的操作数组,这是个原子操作。

    帮助文档信息:

    NAME

    semop, semtimedop - semaphore operations

    SYNOPSIS

    #include <sys/types.h>

    #include <sys/ipc.h>

    #include <sys/sem.h>

    int semop(int semid, struct sembuf *sops, unsigned nsops);

    int semtimedop(int semid, struct sembuf *sops, unsigned nsops,

    struct timespec *timeout);

    Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

    semtimedop(): _GNU_SOURCE

    DESCRIPTION

    Each semaphore in a semaphore set has the following associated values:

    unsigned short semval; /* semaphore value */

    unsigned short semzcnt; /* # waiting for zero */

    unsigned short semncnt; /* # waiting for increase */

    pid_t sempid; /* process that did last op */

    semop() performs operations on selected semaphores in the set indicated by

    semid. Each of the nsops elements in the array pointed to by sops specifies an

    operation to be performed on a single semaphore. The elements of this structure

    are of type struct sembuf, containing the following members:

    unsigned short sem_num; /* semaphore number */

    short sem_op; /* semaphore operation */

    short sem_flg; /* operation flags */

    Flags recognized in sem_flg are IPC_NOWAIT and SEM_UNDO. If an operation speci-

    fies SEM_UNDO, it will be automatically undone when the process terminates.

    The set of operations contained in sops is performed in array order, and atomi-

    cally, that is, the operations are performed either as a complete unit, or not

    at all. The behavior of the system call if not all operations can be performed

    immediately depends on the presence of the IPC_NOWAIT flag in the individual

    sem_flg fields, as noted below.

    Each operation is performed on the sem_num-th semaphore of the semaphore set,

    where the first semaphore of the set is numbered 0. There are three types of

    operation, distinguished by the value of sem_op.

    If sem_op is a positive integer, the operation adds this value to the semaphore

    value (semval). Furthermore, if SEM_UNDO is specified for this operation, the

    system updates the process undo count (semadj) for this semaphore. This opera-

    tion can always proceed — it never forces a process to wait. The calling pro-

    cess must have alter permission on the semaphore set.

    If sem_op is zero, the process must have read permission on the semaphore set.

    This is a "wait-for-zero" operation: if semval is zero, the operation can imme-

    diately proceed. Otherwise, if IPC_NOWAIT is specified in sem_flg, semop()

    fails with errno set to EAGAIN (and none of the operations in sops is per-

    formed). Otherwise semzcnt (the count of processes waiting until this

    semaphore's value becomes zero) is incremented by one and the process sleeps

    until one of the following occurs:

    · semval becomes 0, at which time the value of semzcnt is decremented.

    · The semaphore set is removed: semop() fails, with errno set to EIDRM.

    · The calling process catches a signal: the value of semzcnt is decremented and

    semop() fails, with errno set to EINTR.

    · The time limit specified by timeout in a semtimedop() call expires: semop()

    fails, with errno set to EAGAIN.

    If sem_op is less than zero, the process must have alter permission on the

    semaphore set. If semval is greater than or equal to the absolute value of

    sem_op, the operation can proceed immediately: the absolute value of sem_op is

    subtracted from semval, and, if SEM_UNDO is specified for this operation, the

    system updates the process undo count (semadj) for this semaphore. If the abso-

    lute value of sem_op is greater than semval, and IPC_NOWAIT is specified in

    sem_flg, semop() fails, with errno set to EAGAIN (and none of the operations in

    sops is performed). Otherwise semncnt (the counter of processes waiting for

    this semaphore's value to increase) is incremented by one and the process sleeps

    until one of the following occurs:

    · semval becomes greater than or equal to the absolute value of sem_op, at

    which time the value of semncnt is decremented, the absolute value of sem_op

    is subtracted from semval and, if SEM_UNDO is specified for this operation,

    the system updates the process undo count (semadj) for this semaphore.

    · The semaphore set is removed from the system: semop() fails, with errno set

    to EIDRM.

    · The calling process catches a signal: the value of semncnt is decremented and

    semop() fails, with errno set to EINTR.

    · The time limit specified by timeout in a semtimedop() call expires: the sys-

    tem call fails, with errno set to EAGAIN.

    On successful completion, the sempid value for each semaphore specified in the

    array pointed to by sops is set to the process ID of the calling process. In

    addition, the sem_otime is set to the current time.

    semtimedop() behaves identically to semop() except that in those cases were the

    calling process would sleep, the duration of that sleep is limited by the amount

    of elapsed time specified by the timespec structure whose address is passed in

    the timeout argument. If the specified time limit has been reached, semtime-

    dop() fails with errno set to EAGAIN (and none of the operations in sops is per-

    formed). If the timeout argument is NULL, then semtimedop() behaves exactly

    like semop().

    RETURN VALUE

    If successful semop() and semtimedop() return 0; otherwise they return -1 with

    errno indicating the error.

    ERRORS

    On failure, errno is set to one of the following:

    E2BIG The argument nsops is greater than SEMOPM, the maximum number of opera-

    tions allowed per system call.

    EACCES The calling process does not have the permissions required to perform the

    specified semaphore operations, and does not have the CAP_IPC_OWNER capa-

    bility.

    EAGAIN An operation could not proceed immediately and either IPC_NOWAIT was

    specified in sem_flg or the time limit specified in timeout expired.

    EFAULT An address specified in either the sops or the timeout argument isn't

    accessible.

    EFBIG For some operation the value of sem_num is less than 0 or greater than or

    equal to the number of semaphores in the set.

    EIDRM The semaphore set was removed.

    EINTR While blocked in this system call, the process caught a signal; see sig-

    nal(7).

    EINVAL The semaphore set doesn't exist, or semid is less than zero, or nsops has

    a non-positive value.

    ENOMEM The sem_flg of some operation specified SEM_UNDO and the system does not

    have enough memory to allocate the undo structure.

    ERANGE For some operation sem_op+semval is greater than SEMVMX, the implementa-

    tion dependent maximum value for semval.

    VERSIONS

    semtimedop() first appeared in Linux 2.5.52, and was subsequently backported

    into kernel 2.4.22. Glibc support for semtimedop() first appeared in version

    2.3.3.

    CONFORMING TO

    SVr4, POSIX.1-2001.

    NOTES

    The sem_undo structures of a process aren't inherited by the child produced by

    fork(2), but they are inherited across an execve(2) system call.

    semop() is never automatically restarted after being interrupted by a signal

    handler, regardless of the setting of the SA_RESTART flag when establishing a

    signal handler.

    semadj is a per-process integer which is simply the (negative) count of all

    semaphore operations performed specifying the SEM_UNDO flag. When a semaphore's

    value is directly set using the SETVAL or SETALL request to semctl(2), the cor-

    responding semadj values in all processes are cleared.

    The semval, sempid, semzcnt, and semnct values for a semaphore can all be

    retrieved using appropriate semctl(2) calls.

    The following limits on semaphore set resources affect the semop() call:

    SEMOPM Maximum number of operations allowed for one semop() call (32) (on Linux,

    this limit can be read and modified via the third field of /proc/sys/ker-

    nel/sem).

    SEMVMX Maximum allowable value for semval: implementation dependent (32767).

    The implementation has no intrinsic limits for the adjust on exit maximum value

    (SEMAEM), the system wide maximum number of undo structures (SEMMNU) and the

    per-process maximum number of undo entries system parameters.

    BUGS

    When a process terminates, its set of associated semadj structures is used to

    undo the effect of all of the semaphore operations it performed with the

    SEM_UNDO flag. This raises a difficulty: if one (or more) of these semaphore

    adjustments would result in an attempt to decrease a semaphore's value below

    zero, what should an implementation do? One possible approach would be to block

    until all the semaphore adjustments could be performed. This is however unde-

    sirable since it could force process termination to block for arbitrarily long

    periods. Another possibility is that such semaphore adjustments could be

    ignored altogether (somewhat analogously to failing when IPC_NOWAIT is specified

    for a semaphore operation). Linux adopts a third approach: decreasing the

    semaphore value as far as possible (i.e., to zero) and allowing process termina-

    tion to proceed immediately.

    In kernels 2.6.x, x <= 10, there is a bug that in some circumstances prevents a

    process that is waiting for a semaphore value to become zero from being woken up

    when the value does actually become zero. This bug is fixed in kernel 2.6.11.

    EXAMPLE

    The following code segment uses semop() to atomically wait for the value of

    semaphore 0 to become zero, and then increment the semaphore value by one.

    struct sembuf sops[2];

    int semid;

    /* Code to set semid omitted */

    sops[0].sem_num = 0; /* Operate on semaphore 0 */

    sops[0].sem_op = 0; /* Wait for value to equal 0 */

    sops[0].sem_flg = 0;

    sops[1].sem_num = 0; /* Operate on semaphore 0 */

    sops[1].sem_op = 1; /* Increment value by one */

    sops[1].sem_flg = 0;

    if (semop(semid, sops, 2) == -1) {

    perror("semop");

    exit(EXIT_FAILURE);

    }

    SEE ALSO

    semctl(2), semget(2), sigaction(2), capabilities(7), sem_overview(7), svipc(7),

    time(7)

    COLOPHON

    This page is part of release 3.22 of the Linux man-pages project. A description

    of the project, and information about reporting bugs, can be found at

    http://www.kernel.org/doc/man-pages/.

    该函数里:函数的原型:

    int semop(int semid, struct sembuf *sops, unsigned nsops);

    该函数的功能是操作信号量,通常是以集合出现的。

    需要的头文件:

    #include <sys/types.h>

    #include <sys/ipc.h>

    #include <sys/sem.h>

    该函数的返回值:成功返回0,失败返回-1.

    参数说明:

    semid:要操作的信号量集合的标示符。

    nsops:要操作多少个信号量。

    Sops:对信号量执行的操作:是获取还是释放。获取-1,释放+1.Sem_op:正数是释放,负数是获取。如果获取不成功则会进入等待状态。

    实例:

    semaphoreA.c:

    #include <unistd.h>

    #include <sys/types.h>

    #include <sys/stat.h>

    #include <fcntl.h>

    #include <sys/ipc.h>

    #include <sys/sem.h>

    void main(){

        //open file

        int fd = 0;

        key_t key;

        int semid;

        struct sembuf sops;

        

        key = ftok("/home",1);

        //create semaphore

        semid = semget(key,1,IPC_CREAT);

        fd = open("/home/wen",O_RDWR|O_APPEND);

        //get semaphore

        sops.sem_num = 0;

        sops.sem_op = -1;

        semop(semid,&sops, 1);

        //write something into file

        write(fd,"forfish!",8);

        //rest

        sleep(10);

        //write something else.

        write(fd,"is die!",7);

        //free semaphore

        sops.sem_num = 0;

        sops.sem_op = 1;

        semop(semid,&sops, 1);

        close(fd);

    }

    semaphoreB.c:

    #include <unistd.h>

    #include <sys/types.h>

    #include <sys/stat.h>

    #include <fcntl.h>

    #include <sys/ipc.h>

    #include <sys/sem.h>

    void main(){

        int fd = 0;

        key_t key;

        int semid;

        struct sembuf sops;

        

        key = ftok("/home",1);

        semid = semget(key,1,IPC_CREAT);

        //open sem

        fd = open("/home/wen",O_RDWR|O_APPEND);

        sops.sem_num = 0;

        sops.sem_op = -1;

        semop(semid,&sops, 1);

        write(fd,"fish!",5);

        

        sops.sem_num = 0;

        sops.sem_op = 1;

        semop(semid,&sops, 1);

        close(fd);

    }

    编译运行:

    结果看不见B等待,结果:

    还是没能实现!这是因为我们忽略了信号量的初始值。我们在操作之前应该确保信号量的值是1.所以接下来就是设置我们的信号量为1.

    设置信号量:

    在命令行:man 2 semctl:

    NAME

    semctl - semaphore control operations

    SYNOPSIS

    #include <sys/types.h>

    #include <sys/ipc.h>

    #include <sys/sem.h>

    int semctl(int semid, int semnum, int cmd, ...);

    DESCRIPTION

    semctl() performs the control operation specified by cmd on the semaphore set

    identified by semid, or on the semnum-th semaphore of that set. (The semaphores

    in a set are numbered starting at 0.)

    This function has three or four arguments, depending on cmd. When there are

    four, the fourth has the type union semun. The calling program must define this

    union as follows:

    union semun {

    int val; /* Value for SETVAL */

    struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */

    unsigned short *array; /* Array for GETALL, SETALL */

    struct seminfo *__buf; /* Buffer for IPC_INFO

    (Linux-specific) */

    };

    The semid_ds data structure is defined in <sys/sem.h> as follows:

    struct semid_ds {

    struct ipc_perm sem_perm; /* Ownership and permissions */

    time_t sem_otime; /* Last semop time */

    time_t sem_ctime; /* Last change time */

    unsigned short sem_nsems; /* No. of semaphores in set */

    };

    The ipc_perm structure is defined in <sys/ipc.h> as follows (the highlighted

    fields are settable using IPC_SET):

    struct ipc_perm {

    key_t __key; /* Key supplied to semget(2) */

    uid_t uid; /* Effective UID of owner */

    gid_t gid; /* Effective GID of owner */

    uid_t cuid; /* Effective UID of creator */

    gid_t cgid; /* Effective GID of creator */

    unsigned short mode; /* Permissions */

    unsigned short __seq; /* Sequence number */

    };

    Valid values for cmd are:

    IPC_STAT Copy information from the kernel data structure associated with semid

    into the semid_ds structure pointed to by arg.buf. The argument sem-

    num is ignored. The calling process must have read permission on the

    semaphore set.

    IPC_SET Write the values of some members of the semid_ds structure pointed to

    by arg.buf to the kernel data structure associated with this semaphore

    set, updating also its sem_ctime member. The following members of the

    structure are updated: sem_perm.uid, sem_perm.gid, and (the least sig-

    nificant 9 bits of) sem_perm.mode. The effective UID of the calling

    process must match the owner (sem_perm.uid) or creator (sem_perm.cuid)

    of the semaphore set, or the caller must be privileged. The argument

    semnum is ignored.

    IPC_RMID Immediately remove the semaphore set, awakening all processes blocked

    in semop(2) calls on the set (with an error return and errno set to

    EIDRM). The effective user ID of the calling process must match the

    creator or owner of the semaphore set, or the caller must be privi-

    leged. The argument semnum is ignored.

    IPC_INFO (Linux-specific)

    Returns information about system-wide semaphore limits and parameters

    in the structure pointed to by arg.__buf. This structure is of type

    seminfo, defined in <sys/sem.h> if the _GNU_SOURCE feature test macro

    is defined:

    struct seminfo {

    int semmap; /* Number of entries in semaphore

    map; unused within kernel */

    int semmni; /* Maximum number of semaphore sets */

    int semmns; /* Maximum number of semaphores in all

    semaphore sets */

    int semmnu; /* System-wide maximum number of undo

    structures; unused within kernel */

    int semmsl; /* Maximum number of semaphores in a

    set */

    int semopm; /* Maximum number of operations for

    semop(2) */

    int semume; /* Maximum number of undo entries per

    process; unused within kernel */

    int semusz; /* Size of struct sem_undo */

    int semvmx; /* Maximum semaphore value */

    int semaem; /* Max. value that can be recorded for

    semaphore adjustment (SEM_UNDO) */

    };

    The semmsl, semmns, semopm, and semmni settings can be changed via

    /proc/sys/kernel/sem; see proc(5) for details.

    SEM_INFO (Linux-specific)

    Returns a seminfo structure containing the same information as for

    IPC_INFO, except that the following fields are returned with informa-

    tion about system resources consumed by semaphores: the semusz field

    returns the number of semaphore sets that currently exist on the sys-

    tem; and the semaem field returns the total number of semaphores in

    all semaphore sets on the system.

    SEM_STAT (Linux-specific)

    Returns a semid_ds structure as for IPC_STAT. However, the semid

    argument is not a semaphore identifier, but instead an index into the

    kernel's internal array that maintains information about all semaphore

    sets on the system.

    GETALL Return semval (i.e., the current value) for all semaphores of the set

    into arg.array. The argument semnum is ignored. The calling process

    must have read permission on the semaphore set.

    GETNCNT The system call returns the value of semncnt (i.e., the number of pro-

    cesses waiting for the value of this semaphore to increase) for the

    semnum-th semaphore of the set (i.e., the number of processes waiting

    for an increase of semval for the semnum-th semaphore of the set).

    The calling process must have read permission on the semaphore set.

    GETPID The system call returns the value of sempid for the semnum-th

    semaphore of the set (i.e., the PID of the process that executed the

    last semop(2) call for the semnum-th semaphore of the set). The call-

    ing process must have read permission on the semaphore set.

    GETVAL The system call returns the value of semval for the semnum-th

    semaphore of the set. The calling process must have read permission

    on the semaphore set.

    GETZCNT The system call returns the value of semzcnt (i.e., the number of pro-

    cesses waiting for the value of this semaphore to become zero) for the

    semnum-th semaphore of the set (i.e., the number of processes waiting

    for semval of the semnum-th semaphore of the set to become 0). The

    calling process must have read permission on the semaphore set.

    SETALL Set semval for all semaphores of the set using arg.array, updating

    also the sem_ctime member of the semid_ds structure associated with

    the set. Undo entries (see semop(2)) are cleared for altered

    semaphores in all processes. If the changes to semaphore values would

    permit blocked semop(2) calls in other processes to proceed, then

    those processes are woken up. The argument semnum is ignored. The

    calling process must have alter (write) permission on the semaphore

    set.

    SETVAL Set the value of semval to arg.val for the semnum-th semaphore of the

    set, updating also the sem_ctime member of the semid_ds structure

    associated with the set. Undo entries are cleared for altered

    semaphores in all processes. If the changes to semaphore values would

    permit blocked semop(2) calls in other processes to proceed, then

    those processes are woken up. The calling process must have alter

    permission on the semaphore set.

    RETURN VALUE

    On failure semctl() returns -1 with errno indicating the error.

    Otherwise the system call returns a non-negative value depending on cmd as fol-

    lows:

    GETNCNT the value of semncnt.

    GETPID the value of sempid.

    GETVAL the value of semval.

    GETZCNT the value of semzcnt.

    IPC_INFO the index of the highest used entry in the kernel's internal array

    recording information about all semaphore sets. (This information

    can be used with repeated SEM_STAT operations to obtain information

    about all semaphore sets on the system.)

    SEM_INFO As for IPC_INFO.

    SEM_STAT the identifier of the semaphore set whose index was given in semid.

    All other cmd values return 0 on success.

    ERRORS

    On failure, errno will be set to one of the following:

    EACCES The argument cmd has one of the values GETALL, GETPID, GETVAL, GETNCNT,

    GETZCNT, IPC_STAT, SEM_STAT, SETALL, or SETVAL and the calling process

    does not have the required permissions on the semaphore set and does not

    have the CAP_IPC_OWNER capability.

    EFAULT The address pointed to by arg.buf or arg.array isn't accessible.

    EIDRM The semaphore set was removed.

    EINVAL Invalid value for cmd or semid. Or: for a SEM_STAT operation, the index

    value specified in semid referred to an array slot that is currently

    unused.

    EPERM The argument cmd has the value IPC_SET or IPC_RMID but the effective user

    ID of the calling process is not the creator (as found in sem_perm.cuid)

    or the owner (as found in sem_perm.uid) of the semaphore set, and the

    process does not have the CAP_SYS_ADMIN capability.

    ERANGE The argument cmd has the value SETALL or SETVAL and the value to which

    semval is to be set (for some semaphore of the set) is less than 0 or

    greater than the implementation limit SEMVMX.

    CONFORMING TO

    SVr4, POSIX.1-2001.

    NOTES

    The IPC_INFO, SEM_STAT and SEM_INFO operations are used by the ipcs(8) program

    to provide information on allocated resources. In the future these may modified

    or moved to a /proc file system interface.

    Various fields in a struct semid_ds were typed as short under Linux 2.2 and have

    become long under Linux 2.4. To take advantage of this, a recompilation under

    glibc-2.1.91 or later should suffice. (The kernel distinguishes old and new

    calls by an IPC_64 flag in cmd.)

    In some earlier versions of glibc, the semun union was defined in <sys/sem.h>,

    but POSIX.1-2001 requires that the caller define this union. On versions of

    glibc where this union is not defined, the macro _SEM_SEMUN_UNDEFINED is defined

    in <sys/sem.h>.

    The following system limit on semaphore sets affects a semctl() call:

    SEMVMX Maximum value for semval: implementation dependent (32767).

    For greater portability it is best to always call semctl() with four arguments.

    SEE ALSO

    ipc(2), semget(2), semop(2), capabilities(7), sem_overview(7), svipc(7)

    COLOPHON

    This page is part of release 3.22 of the Linux man-pages project. A description

    of the project, and information about reporting bugs, can be found at

    http://www.kernel.org/doc/man-pages/.

    该函数的原型:

    int semctl(int semid, int semnum, int cmd, ...);

    第一个参数是要操作信号量的集合,第二个是集合里的第几个信号,第三个参数是命令,即是进行的操作:

    GETNCNT the value of semncnt.

    GETPID the value of sempid.

    GETVAL the value of semval.

    GETZCNT the value of semzcnt.

    IPC_INFO the index of the highest used entry in the kernel's internal array

    recording information about all semaphore sets. (This information

    can be used with repeated SEM_STAT operations to obtain information

    about all semaphore sets on the system.)

    SEM_INFO As for IPC_INFO.

    SEM_STAT the identifier of the semaphore set whose index was given in semid.

    返回值就是信号量的值。

    semaphoreA.c:

    #include <unistd.h>

    #include <sys/types.h>

    #include <sys/stat.h>

    #include <fcntl.h>

    #include <sys/ipc.h>

    #include <sys/sem.h>

    void main(){

        //open file

        int fd = 0;

        key_t key;

        int semid;

        struct sembuf sops;

        int temp;

        

        key = ftok("/home",1);

        //create semaphore

        semid = semget(key,1,IPC_CREAT);

        temp = semctl(semid,0,GETVAL);

        printf("sem of init is %d ",temp);

        fd = open("/home/wen",O_RDWR|O_APPEND);

        //get semaphore

        sops.sem_num = 0;

        sops.sem_op = -1;

        semop(semid,&sops, 1);

        //write something into file

        write(fd,"forfish!",8);

        //rest

        sleep(10);

        //write something else.

        write(fd,"is die!",7);

        //free semaphore

        sops.sem_num = 0;

        sops.sem_op = 1;

        semop(semid,&sops, 1);

        close(fd);

    }

    运行的效果:

    我们看到信号量的初值为2,所以我们上面才会失败。所以我们需要把信号量的初值设置为1.也是在semctl函数修改:

    temp = semctl(semid,0,GETVAL,1);

    最后的代码:

    semaphoreA.c:

    #include <unistd.h>

    #include <sys/types.h>

    #include <sys/stat.h>

    #include <fcntl.h>

    #include <sys/ipc.h>

    #include <sys/sem.h>

    void main(){

        //open file

        int fd = 0;

        key_t key;

        int semid;

        struct sembuf sops;

        int temp;

        

        key = ftok("/home",1);

        //create semaphore

        semid = semget(key,1,IPC_CREAT);

        temp = semctl(semid,0,SETVAL,1);

        printf("sem of init is %d ",temp);

        fd = open("/home/wen",O_RDWR|O_APPEND);

        //get semaphore

        sops.sem_num = 0;

        sops.sem_op = -1;

        semop(semid,&sops, 1);

        //write something into file

        write(fd,"forfish!",8);

        //rest

        sleep(10);

        //write something else.

        write(fd,"is die!",7);

        //free semaphore

        sops.sem_num = 0;

        sops.sem_op = 1;

        semop(semid,&sops, 1);

        close(fd);

    }

    semaphoreB.c:

    #include <unistd.h>

    #include <sys/types.h>

    #include <sys/stat.h>

    #include <fcntl.h>

    #include <sys/ipc.h>

    #include <sys/sem.h>

    void main(){

        int fd = 0;

        key_t key;

        int semid;

        struct sembuf sops;

        int temp;

        

        key = ftok("/home",1);

        semid = semget(key,1,IPC_CREAT);

        //open sem

        temp = semctl(semid,0,GETVAL,1);

        printf("sem of value is %d ",temp);

        fd = open("/home/wen",O_RDWR|O_APPEND);

        sops.sem_num = 0;

        sops.sem_op = -1;

        semop(semid,&sops, 1);

        write(fd,"fish!",5);

        

        sops.sem_num = 0;

        sops.sem_op = 1;

        semop(semid,&sops, 1);

        close(fd);

    }

    运行结果:

    写入的结果:

    可以看到现在两个进程往同一个文件写入内容就不会混乱了。这是因为我们设置了初始的信号量是1,当semaphoreA往里面写东西,然后休息10秒,由于在这段时间,信号量被A占有着,没有释放。所以即使B想往该文件写入内容。因为此时被A占有着,信号量为0,此时B只能等待。我们看到执行中,B确实在等待。直到A写完成,释放了信号量。B才能占有信号量,往文件写内容。显示的结果和我们想要的一样。操作成功。

  • 相关阅读:
    (转)if __name__ == '__main__' 如何正确理解?
    (转)Django配置mysql数据库
    (转)Python虚拟环境pyenv、venv(pyvenv)、virtualenv之间的区别,终于搞清楚了!
    找出Framework 4.0 新增的方法和新增的类(下)
    C# MBG 扩展方法类库 分享
    是技术还是态度,网易的视频Title
    不要返回null之EmptyFactory
    你知道这段代码的输出吗?
    C# 4.0 大数的运算,BigInteger
    CleanCode: 面向过程 PK 面向对象
  • 原文地址:https://www.cnblogs.com/FORFISH/p/5188658.html
Copyright © 2011-2022 走看看