17.信号量同步编程

17.信号量同步编程

进程同步:

一组并发进程进行互相合作、互相等待,使得各进程按一定的顺序执行的过程称为进程间的同步。

生产者:1.创建文件。2.往文件写内容。(中间有sleep)。

进程同步中经典的实例:生产者与消费者的问题。

Producer.c:

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

#include <fcntl.h>

void main(){

    int fd;

    //create product

    fd = open("/home/zhu",O_RDWR | O_CREAT,0777);

    sleep(20);

    //completing product

    write(fd,"the product is complete!",24);

    close(fd);

}

consumer.c:

#include <stdlib.h>

#include <stdio.h>

void main(){

    //take away product

    system("cp /home/zhu ./");

}

运行的结果:

我们看到产品是生产出来了,可是一个半成品,里面啥内容都没。这是因为我们的生产者,在生产东西的时候,还没完成,中途有事出去,然后消费者不知道产品还没完成就取走了。

    

这个问题和前面的信号量互斥有点相似:我们把信号量的初始值设置为0(与互斥不同),然后我们生产者不用获取信号量,他需要的是释放信号量,就是他完成生产一件产品之后要释放信号量。切记是在生产好了一件产品后释放信号量。就是生产者不获取信号量,只释放信号量。由于我们信号量的初始值是0,无法获取信号量,就是消费者不能拿走产品,因为信号量为0,这就确保了产品只有完成才能让消费者拿走,注意的是,我们的消费者不用释放信号量。

运行的结果:

Productor1.c:

#include <sys/types.h>

#include <sys/ipc.h>

#include <stdlib.h>

#include <sys/sem.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

void main(){

    int fd;

    key_t key;

    int semid;

    struct sembuf sops;

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

    

    //create semaphore

    semid = semget(key,1,IPC_CREAT);

    semctl(semid,0,SETVAL,0);

    //create product

    fd = open("/home/zhu",O_RDWR | O_CREAT,0777);

    sleep(20);

    //completing product

    write(fd,"the product is complete!",24);

    //free

    sops.sem_num = 0;

    sops.sem_op = 1;

    sops.sem_flg = SEM_UNDO;

    semop(semid,&sops,1);

    close(fd);

}

consumer1.c:

#include <sys/types.h>

#include <sys/ipc.h>

#include <stdlib.h>

#include <sys/sem.h>

void main(){

    key_t key;

    int semid;

    struct sembuf sops;

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

    

    //create semaphore

    semid = semget(key,1,IPC_CREAT);

    //get semaphore

    sops.sem_num = 0;

    sops.sem_op = -1;

    sops.sem_flg = SEM_UNDO;//free

    semop(semid,&sops,1);

    //take product

    system("cp /home/zhu ./");

}

运行的结果:

拿走成功:

我们就实现了只有生产者生产好了产品,消费者才能拿走的机制。

我们在消费者程序中用到system函数:

man 3 system:的信息:

NAME

system - execute a shell command

SYNOPSIS

#include <stdlib.h>

int system(const char *command);

DESCRIPTION

system() executes a command specified in command by calling /bin/sh -c command,

and returns after the command has been completed. During execution of the com-

mand, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored.

RETURN VALUE

The value returned is -1 on error (e.g. fork(2) failed), and the return status

of the command otherwise. This latter return status is in the format specified

in wait(2). Thus, the exit code of the command will be WEXITSTATUS(status). In

case /bin/sh could not be executed, the exit status will be that of a command

that does exit(127).

If the value of command is NULL, system() returns non-zero if the shell is

available, and zero if not.

system() does not affect the wait status of any other children.

CONFORMING TO

C89, C99, POSIX.1-2001.

NOTES

If the _XOPEN_SOURCE feature test macro is defined, then the macros described in

wait(2) (WEXITSTATUS(), etc.) are made available when including <stdlib.h>.

As mentioned, system() ignores SIGINT and SIGQUIT. This may make programs that

call it from a loop uninterruptible, unless they take care themselves to check

the exit status of the child. E.g.

while (something) {

int ret = system("foo");

if (WIFSIGNALED(ret) &&

(WTERMSIG(ret) == SIGINT || WTERMSIG(ret) == SIGQUIT))

break;

}

Do not use system() from a program with set-user-ID or set-group-ID privileges,

because strange values for some environment variables might be used to subvert

system integrity. Use the exec(3) family of functions instead, but not exe-

clp(3) or execvp(3). system() will not, in fact, work properly from programs

with set-user-ID or set-group-ID privileges on systems on which /bin/sh is bash

version 2, since bash 2 drops privileges on startup. (Debian uses a modified

bash which does not do this when invoked as sh.)

In versions of glibc before 2.1.3, the check for the availability of /bin/sh was

not actually performed if command was NULL; instead it was always assumed to be

available, and system() always returned 1 in this case. Since glibc 2.1.3, this

check is performed because, even though POSIX.1-2001 requires a conforming

implementation to provide a shell, that shell may not be available or executable

if the calling program has previously called chroot(2) (which is not specified

by POSIX.1-2001).

It is possible for the shell command to return 127, so that code is not a sure

indication that the execve(2) call failed.

SEE ALSO

sh(1), signal(2), wait(2), exec(3)

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/.

原文地址:https://www.cnblogs.com/FORFISH/p/5188659.html