Linux下的简单生产、消费模型的实现(上)

生产消费模型是信号量的最典型的应用实例。然而实际操作系统中PV操作并不是如理想模型那样方便使用的,这里以Linux为例描述了生产、消费模型的实现方法,同时涉及了Linux下共享内存、信号量的基本操作。如有不正确之处,请大家指正,谢谢! 

一、Linux下信号量的建立

要建立一个信号量,首先要给信号量一个主键,即给信号量命名。Linux下的信号量与Windows有很大的不同,Windows以一个字符串来命名一个信号量,而Linux则以一个t_key类型的数值命名一组信号量。为了方便调试一般我们会在公共头文件中,以宏定义的方式进行信号量的命名,比如 

#define KEY_MUTEX ((key_t) 403040914 )

Linux下信号量集合的新建使用如下库函数

#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg); 

其中key就是前文所说的主键,nsems是集合中包含的元素个数,semflg则是用于新建信号量的重要参数,比如访问控制权限。返回值是以key为主键的信号量标号,若返回-1说明产生了操作错误。具体参数的说明请看http://www.opengroup.org/onlinepubs/007908799/xsh/semget.html

为了方便理解与操作,这里我们需要建立的是仅有一个元素的公有信号量集。代码如下 

id = semget(KEY_MUTEX, 1, IPC_CREAT|0660); 

其中,一定要注意0660最高位的0不能省略,因为这是一个八进制数,代表rw-rw----的访问控制。 

二、信号量的初始化

信号量建立之后必须要进行初始化,在Linux信号的基本控制使用统一的API函数: 

#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);

其中semnum是集合中元素的序号(以0开始计算);cmd则是需要进行的控制命令,在sys/sem.h 头文件中有宏定义,我们使用的是设置值SETVAL;附加参数可以接受如下的联合体(需要用户自行定义)。具体说明见http://www.opengroup.org/onlinepubs/007908799/xsh/semctl.html

union semun
{
    int val;                  /* value for SETVAL */
    struct semid_ds *buf;     /* buffer for IPC_STAT, IPC_SET */
    unsigned short *array;    /* array for GETALL, SETALL */
                                  /* Linux specific part: */
    struct seminfo *__buf;    /* buffer for IPC_INFO */
};

这里我们假设要将信号量集中第一个元素(也是唯一一个元素)赋初值1,使用如下代码

union semun un;
un.val = 1;
semctl(id, 0, SETVAL, un);

三、信号量的PV操作

在教科书里PV操作是两个完全不同的操作,但是在Linux系统中PV操作则在形式上统一为一个API函数。而且由于Linux下信号量集合的特点,一个调用可以同时作用于多个信号量元素中。函数原型如下:

#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, size_t nsops);  

其中sops是一个sembuf结构体类型的数组,数组的每一个元素就是对一个信号量的操作,nsops则指出了数组的长度(操作的个数)。此结构体有三个成员

short sem_num 信号量元素序号(0起始)
short sem_op 操作数值
short sem_flg 操作标记

对于P操作有sem_op=-1,对于V操作有sem_op=1。操作之后,若信号量小于零则semop()调用被挂起直到大于等于0时才返回。我使用wait()release()两个函数分别实现了P操作和V操作:

void wait(int id)
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = -1;
    buf.sem_flg = SEM_UNDO;
    semop(id, &buf, 1);
}

void release(int id)
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = 1;
    buf.sem_flg = SEM_UNDO;
    semop(id, &buf, 1);
}

至于信号量的删除,亦是使用semctl()调用,但是由于涉及收到SIGKILL信号后的处理所以不作详细介绍了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux下的生产消费模型可以使用pthread库中的互斥锁和条件变量来实现同步。下面是一个简单生产消费模型的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #define BUFFER_SIZE 10 int buffer[BUFFER_SIZE]; int in = 0, out = 0; int count = 0; pthread_mutex_t mutex; pthread_cond_t not_full; pthread_cond_t not_empty; void *producer(void *arg); void *consumer(void *arg); int main() { pthread_t tid_producer, tid_consumer; // 初始化互斥锁和条件变量 pthread_mutex_init(&mutex, NULL); pthread_cond_init(&not_full, NULL); pthread_cond_init(&not_empty, NULL); // 创建生产者和消费者线程 pthread_create(&tid_producer, NULL, producer, NULL); pthread_create(&tid_consumer, NULL, consumer, NULL); // 等待线程结束 pthread_join(tid_producer, NULL); pthread_join(tid_consumer, NULL); // 销毁互斥锁和条件变量 pthread_mutex_destroy(&mutex); pthread_cond_destroy(&not_full); pthread_cond_destroy(&not_empty); return 0; } void *producer(void *arg) { while (1) { pthread_mutex_lock(&mutex); if (count == BUFFER_SIZE) { // 缓冲区已满,等待消费消费 pthread_cond_wait(&not_full, &mutex); } // 生产生产一个数据,并将其放入缓冲区 int item = rand() % 100; buffer[in] = item; in = (in + 1) % BUFFER_SIZE; count++; printf("producer: produce item %d, buffer count = %d\n", item, count); // 通知消费者可以消费了 pthread_cond_signal(&not_empty); pthread_mutex_unlock(&mutex); } } void *consumer(void *arg) { while (1) { pthread_mutex_lock(&mutex); if (count == 0) { // 缓冲区为空,等待生产生产 pthread_cond_wait(&not_empty, &mutex); } // 消费消费一个数据,并从缓冲区中删除 int item = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; printf("consumer: consume item %d, buffer count = %d\n", item, count); // 通知生产者可以生产了 pthread_cond_signal(&not_full); pthread_mutex_unlock(&mutex); } } ``` 在上述代码中,生产者线程每次生产一个数据并将其放入缓冲区,如果缓冲区已满,则等待消费消费消费者线程每次从缓冲区中取出一个数据并将其消费,如果缓冲区为空,则等待生产生产。使用互斥锁保证在访问共享资源时不会出现竞争条件,使用条件变量实现生产者和消费者之间的同步。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值