Linux进程互斥——生产者-消费者

经典的进程同步问题——生产者-消费者

  • 模拟生产者-消费者的示例程序
    • 示例程序代码
      • 运行结果
    • 改造程序,取消所有的同步机制,记录执行情况并进行分析
      • 代码如下
      • 运行结果

模拟生产者-消费者的示例程序

本示例主要体现进程间的直接制约关系,由于使用共享存储区,也存在间接制约关系。进程分为服务进程和客户进程,服务进程只有一个,作为消费者,在每次客户进程改变共享存储区内容时显示其数值。各客户进程作为生产者,如果共享存储区内容已经显示(被消费),可以接收用户从键盘输入的整数,放在共享存储区。

编译后执行,第一个进程实例将作为服务进程,提示:
ACT CONSUMER!!! To end, try Ctrl+C or use kill.
服务进程一直循环执行,直到用户按Ctrl+C终止执行,或使用kill命令杀死服务进程。

其他进程实例作为客户进程,提示:
Act as producer. To end, input 0 when prompted.
客户进程一直循环执行,直到用户输入0。

示例程序代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MY_SHMKEY 10071500		// need to change
#define MY_SEMKEY 10071500		// need to change

void sigend(int);
int shmid, semid;

int main(void)
{
    int *shmptr, semval, local;
    struct sembuf semopbuf;

    if((shmid=shmget(MY_SHMKEY, sizeof(int), IPC_CREAT|IPC_EXCL|0666)) < 0)
    {			/* shared memory exists, act as client */
        shmid=shmget(MY_SHMKEY, sizeof(int), 0666);
        semid=semget(MY_SEMKEY, 2, 0666);
        shmptr=(int *)shmat(shmid, 0, 0);
        printf("Act as producer. To end, input 0 when prompted.\n\n");
	printf("Input a number:\n");
	scanf("%d", &local);
        while( local )
	{
	    semopbuf.sem_num=0;
	    semopbuf.sem_op=-1;
	    semopbuf.sem_flg=SEM_UNDO;
	    semop(semid, &semopbuf, 1);	/* P(S1) */
	    *shmptr = local;
	    semopbuf.sem_num=1;
	    semopbuf.sem_op=1;
	    semopbuf.sem_flg=SEM_UNDO;
	    semop(semid, &semopbuf, 1);	/* V(S2) */
	    printf("Input a number:\n");
	    scanf("%d", &local);
        }
    }
    else		/* acts as server */
    {
        semid=semget(MY_SEMKEY, 2, IPC_CREAT|0666);
        shmptr=(int *)shmat(shmid, 0, 0);
	semval=1;
	semctl(semid, 0, SETVAL, semval);	/* set S1=1 */
	semval=0;
	semctl(semid, 1, SETVAL, semval);	/* set S2=0 */
        signal(SIGINT, sigend);
        signal(SIGTERM, sigend);
        printf("ACT CONSUMER!!! To end, try Ctrl+C or use kill.\n\n");
        while(1)
        {
	    semopbuf.sem_num=1;
	    semopbuf.sem_op=-1;
	    semopbuf.sem_flg=SEM_UNDO;
	    semop(semid, &semopbuf, 1);	/* P(S2) */
            printf("Shared memory set to %d\n", *shmptr);
	    semopbuf.sem_num=0;
	    semopbuf.sem_op=1;
	    semopbuf.sem_flg=SEM_UNDO;
	    semop(semid, &semopbuf, 1);	/* V(S1) */
        }
    }
}

void sigend(int sig)
{
    shmctl(shmid, IPC_RMID, 0);
    semctl(semid, IPC_RMID, 0);
    exit(0);
}

运行结果

Linux进程互斥——生产者-消费者_第1张图片
结果分析:
第一次执行程序,创建公共存储区成功。If条件不成立,进入else分支,创建了一个服务进程:消费者。因公共存储区为空,故消费者进程处于等待状态。
第二次执行该程序,创建公共存储区失败,条件成立,进入if分支,即:创建一个客户进程:生产者。生产者提示输入一个整数,输入后,生产者将该整数保存到公共存储区,此时消费者会唤醒进行消费,把数据读出并输出。

改造程序,取消所有的同步机制,记录执行情况并进行分析

改造该程序,取消所有的同步机制:
即去掉实现wait(full) signal(empty) 和 wait(empty) signal(full)的语句semop(semid, &semopbuf, 1);和semop(semid, &semopbuf, 1);
并在消费者进程中添加语句sleep(5),使错误易于观察

代码如下

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MY_SHMKEY 10071500		// need to change
#define MY_SEMKEY 10071500		// need to change

void sigend(int);

int shmid, semid;

int main(void)
{
    int *shmptr, semval, local;
    struct sembuf semopbuf;

    if((shmid=shmget(MY_SHMKEY, sizeof(int), IPC_CREAT|IPC_EXCL|0666)) < 0)
    {			/* shared memory exists, act as client */
        shmid=shmget(MY_SHMKEY, sizeof(int), 0666);
        semid=semget(MY_SEMKEY, 2, 0666);
        shmptr=(int *)shmat(shmid, 0, 0);
        printf("Act as producer. To end, input 0 when prompted.\n\n");
	printf("Input a number:\n");
	scanf("%d", &local);
        while( local )
	{
	    semopbuf.sem_num=0;
	    semopbuf.sem_op=-1;
	    semopbuf.sem_flg=SEM_UNDO;
	    //semop(semid, &semopbuf, 1);	/* P(S1) */
	    *shmptr = local;
	    semopbuf.sem_num=1;
	    semopbuf.sem_op=1;
	    semopbuf.sem_flg=SEM_UNDO;
	    //semop(semid, &semopbuf, 1);	/* V(S2) */
	    printf("Input a number:\n");
	    scanf("%d", &local);
        }
    }
    else		/* acts as server */
    {
        semid=semget(MY_SEMKEY, 2, IPC_CREAT|0666);
        shmptr=(int *)shmat(shmid, 0, 0);
	semval=1;
	semctl(semid, 0, SETVAL, semval);	/* set S1=1 */
	semval=0;
	semctl(semid, 1, SETVAL, semval);	/* set S2=0 */
        signal(SIGINT, sigend);
        signal(SIGTERM, sigend);
        printf("ACT CONSUMER!!! To end, try Ctrl+C or use kill.\n\n");
        while(1)
        {
	    semopbuf.sem_num=1;
	    semopbuf.sem_op=-1;
	    semopbuf.sem_flg=SEM_UNDO;
        sleep(5);
	   //semop(semid, &semopbuf, 1);	/* P(S2) */
            printf("Shared memory set to %d\n", *shmptr);
	    semopbuf.sem_num=0;
	    semopbuf.sem_op=1;
	    semopbuf.sem_flg=SEM_UNDO;
	   //semop(semid, &semopbuf, 1);	/* V(S1) */
        }
    }
}

void sigend(int sig)
{
    shmctl(shmid, IPC_RMID, 0);
    semctl(semid, IPC_RMID, 0);
    exit(0);
}

运行结果

Linux进程互斥——生产者-消费者_第2张图片

结果分析
第一次执行程序,可以看到刚开始输出“Shared memory set to 0”;第二次执行程序,生产者依次生产1,2,3,4,5,由于sleep(5),消费者只消费了“5”,而且多次消费。即,生产者没生产时,消费者已经开始消费了。并且生产者生产一个,而消费者却消费多次。故,程序出现错误。

你可能感兴趣的:(操作系统,linux,ubuntu,c语言)