嵌入式Linux基础学习笔记-文件IO编程-文件锁(2)

文件操作仿真FIFO,实现生产者-消费者运行模型

  1. 编程实现生产者程序producer.c,创建仿真FIFO结构文件(普通文件),按照给定的时间间隔向FIFO文件写入自动生成的字符(自定义),生产周期及生产的资源数通过参数传递给进程。
  2. 编程实现消费者程序customer.c,从文件中读取相应数目的字符并在屏幕上显示,然后从文件中删除刚才消费过的数据,可通过两次幅值来实现文件内容的偏移,每次消费的资源通过参数传递给进程。
  3. 在两个终端上分别运行生产者程序producer和消费者程序customer

生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。
该问题描述了共享固定大小缓冲区的两个线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
.
要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。

在这里插入图片描述

  1. 建立lock_set.c文件
/* lock_set.c */
int lock_set(int fd, int type)
{
	struct flock old_lock, lock;
	lock.l_whence = SEEK_SET;
	lock.l_start = 0;
	lock.l_len = 0;
	lock.l_type = type;
	lock.l_pid = -1;
	/* 判断文件是否可以上锁 */
	fcntl(fd, F_GETLK, &lock);
	if (lock.l_type != F_UNLCK)
	{
		/* 判断文件不能上锁的原因 */
		if (lock.l_type == F_RDLCK) /* 该文件已有读取锁 */
		{
			printf("Read lock already set by %d\n", lock.l_pid);
		}
		else if (lock.l_type == F_WRLCK) /* 该文件已有写入锁 */
		{
			printf("Write lock already set by %d\n", lock.l_pid);
		}			
	}
	/* l_type 可能已被F_GETLK修改过 */
	lock.l_type = type;
	/* 根据不同的type值进行阻塞式上锁或解锁 */
	if ((fcntl(fd, F_SETLKW, &lock)) < 0)
	{
		printf("Lock failed:type = %d\n", lock.l_type);
		return 1;
	}	
	switch(lock.l_type)
	{
		case F_RDLCK:
		{
			printf("Read lock set by %d\n", getpid());
		}
		break;

		case F_WRLCK:
		{
			printf("Write lock set by %d\n", getpid());
		}
		break;
		case F_UNLCK:
		{
			printf("Release lock by %d\n", getpid());
			return 1;
		}
		break;
		default:
		break;
	}/* end of switch  */	
	return 0;
}
  1. 编写生产者程序:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "lock_set.c"

#define MAXLEN 10 /* 缓冲区大小大值 */
#define ALPHABET 1 /* 表示使用英文字符 */
#define ALPHABET_START 'a' /* 头一个字符,可以用 'A' */
#define COUNT_OF_ALPHABET 26 /* 字母字符的个数 */

#define DIGIT 2 /* 表示使用数字字符 */
#define DIGIT_START '0' /* 头一个字符 */
#define COUNT_OF_DIGIT 10 /* 数字字符的个数 */

#define SIGN_TYPE ALPHABET /* 本实例选用英文字符 */
const char *fifo_file = "./myfifo";/* 仿真FIFO文件名 */
char buff[MAXLEN]; /* 缓冲区 */

/* 功能:生产一个字符并写入到仿真FIFO文件中 */
int product(void)
{
    int fd;
    unsigned int sign_type, sign_start, sign_count, size;
    static unsigned int counter = 0;

    /* 打开仿真FIFO文件 */
    if ((fd = open(fifo_file, O_CREAT|O_RDWR|O_APPEND, 0644)) < 0)
    {
        printf("Open fifo file error\n");
        exit(1);
    }

    sign_type = SIGN_TYPE;
    switch(sign_type)
    {
        case ALPHABET:/* 英文字符 */
        {
            sign_start = ALPHABET_START;
            sign_count = COUNT_OF_ALPHABET;
        }
        break;

        case DIGIT:/* 数字字符 */
        {
            sign_start = DIGIT_START;
            sign_count = COUNT_OF_DIGIT;
        }
        break;

        default:
        {
            return -1;
        }
    }/*end of switch*/

    sprintf(buff, "%c", (sign_start + counter));
    counter = (counter + 1) % sign_count;

    lock_set(fd, F_WRLCK); /* 上写锁 */
    if ((size = write(fd, buff, strlen(buff))) < 0)
    {
        printf("Producer: write error\n");
        return -1;
    }
    lock_set(fd, F_UNLCK); /* 解锁 */

    close(fd);
    return 0;
}

int main(int argc ,char *argv[])
{
    int time_step = 1; /* 生产周期 */
    int time_life = 10; /* 需要生产的资源总数 */

    if (argc > 1)
    {/* 第一个参数表示生产周期 */
        sscanf(argv[1], "%d", &time_step);
    }
    if (argc > 2)
    {/* 第二个参数表示需要生产的资源数 */
        sscanf(argv[2], "%d", &time_life);
    }
    while (time_life--)
    {
        if (product() < 0)
        {
            break;
        }
        sleep(time_step);
    }

    exit(EXIT_SUCCESS);
}

  1. 编写消费者程序:
/* customer.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#define MAX_FILE_SIZE 100 * 1024 * 1024 /* 100M*/
const char *fifo_file = "./myfifo"; /* 仿真FIFO文件名 */
const char *tmp_file = "./tmp"; /* 临时文件名 */
/* 资源消费函数 */
int customing(const char *myfifo, int need)
{
    int fd;
    char buff;
    int counter = 0;
    if ((fd = open(myfifo, O_RDONLY)) < 0)
    {
        printf("Function customing error\n");
        return -1;
    }
    printf("Enjoy:");
    lseek(fd, SEEK_SET, 0);
    while (counter < need)
    {
        while ((read(fd, &buff, 1) == 1) && (counter < need))
        {
            fputc(buff, stdout); /* 消费就是在屏幕上简单的显示 */
            counter++;
        }
    }
    fputs("\n", stdout);
    close(fd);
    return 0;
}
/* 功能:从sour_file文件的offset偏移处开始将count字节大小的数据拷贝到dest_file文件 */
int myfilecopy(const char *sour_file, const char *dest_file, int offset,
int count, int copy_mode)
{
    int in_file, out_file;
    int counter = 0;
    char buff_unit;
    if ((in_file = open(sour_file,O_RDONLY|O_NONBLOCK))<0)
    {
        printf("Function myfilecopy error in source file\n");
        return -1;
    }
    if((out_file=open(dest_file,
    O_CREAT|O_RDWR|O_TRUNC|O_NONBLOCK, 0644)) < 0)
    {
        printf("Function myfilecopy errorin
        destination file:");
        return -1;
    }
    lseek(in_file, offset, SEEK_SET);
    while((read(in_file,&buff_unit,1)==1)&&(counter<count))
    {
        write(out_file, &buff_unit, 1);
        counter++;
    }
    close(in_file);
    close(out_file);
    return 0;
    }

/* 功能:实现FIFO消费者 */
int custom(int need)
{
    int fd;
    /* 对资源进行消费,need表示该消费的资源数目 */
    customing(fifo_file, need);
    if ((fd = open(fifo_file, O_RDWR)) < 0)
    {
        printf("Function myfilecopy error in source_file:");
        return -1;
    }
    /* 为了模拟FIFO结构,对整个文件内容进行平行移动 */
    lock_set(fd, F_WRLCK);
    myfilecopy(fifo_file, tmp_file, need, MAX_FILE_SIZE, 0);
    myfilecopy(tmp_file, fifo_file, 0, MAX_FILE_SIZE, 0);
    lock_set(fd, F_UNLCK);
    unlink(tmp_file);
    close(fd);
    return 0;
}
int main(int argc ,char *argv[])
{
    int customer_capacity = 10;
    if (argc > 1) /* 第一个参数指定需要消费的资源数目,默认值为10 */
    {
        sscanf(argv[1], "%d", &customer_capacity);
    }
    if (customer_capacity > 0)
    {
        custom(customer_capacity);
    }
    exit(EXIT_SUCCESS);
}
  1. 测试-生产者程序
    在这里插入图片描述
  2. 测试-消费者程序
    在这里插入图片描述
  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值