菜鸟偶遇信号量,擦出火花(只有不熟才会有火花)。于是上网搜资料和看《Unix环境高级编程》实现了几个小例题,高手请勿喷!这几位写得非常好啊:

题目来源: http://www.it165.net/os/html/201312/7039.html

信号量及其用法:http://www.cnblogs.com/hjslovewcl/archive/2011/03/03/2314341.html

Mutex与Semaphore区别著名的厕所理论:http://koti.mbnet.fi/niclasw/MutexSemaphore.html

  哎呀,暴露了!我不是故意偷窥别人的……




一:一个生产者、一个消费者、一个资源情况

  这种情况情况可以只用一个信号量,要生成或要消费只用尝试获取这个信号量,这里用了两个:full=1和empty=0,两个只为了和后面一致,1、0是赋初值。生产者和消费者情况如下:

//生产者:
P(empty)
生成资源并放进资源处
V(full) //消费者:
P(full)
消费资源
V(empty)

  若生产者最先开始生产资源,P(empty),full和empty都成了0,此时若消费者想要消费,则P(full)时,full为0则睡眠等待,等生产者生结束就把full加1,看到消费者可怜地睡着了就唤醒它,然后消费者把full减1自己快活去了。

  消费者消费过程中生产者若要生了,则会因为empty为0而休眠,等消费者结束就把empty加1,然后生产者开始生产。

  上面的好理解,下面上代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h> #include <x86_64-linux-gnu/sys/types.h>
#include <x86_64-linux-gnu/sys/ipc.h>
#include <x86_64-linux-gnu/sys/sem.h> int semInite(int semId, int value);
int semDelete(int semId);
int semP(int semId);
int semV(int semId); //declare a union to be used
union semun
{
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
unsigned short int *array; /* array for GETALL, SETALL */
struct seminfo *__buf; /* buffer for IPC_INFO */
}; //semaphore declare
static int semFullId;
static int semEmptyId;
static int source = ; //source definition //new thread as a consumer
void* child_thread(void* arg)
{
int ttt = ; while()
{
sleep(rand() % );
printf("child No.%d times wants to consume...\n", ttt); semP(semFullId); //
printf("child No.%d times start consuming. source = %d\n", ttt, source);
source = ;
printf("child No.%d times end consuming. source = %d\n\n", ttt++, source);
semV(semEmptyId); //
} return (void*);
} int main(void)
{
//create semaphore
semFullId = semget((key_t), , | IPC_CREAT);
semEmptyId = semget((key_t), , | IPC_CREAT);
semInite(semFullId, );
semInite(semEmptyId, ); pthread_t pid;
pthread_create(&pid, NULL, child_thread, NULL); int tt = ;
while()
{
sleep(rand() % );
printf("parent No.%d times wants to produce...\n", tt); semP(semEmptyId); //
printf("parent No.%d times start producing. source = %d\n", tt, source);
source = rand() % ;
printf("parent No.%d times end producing. source = %d\n", tt++, source);
semV(semFullId); //
} semDelete(semFullId);
semDelete(semEmptyId);
return ;
} //set semaphore as default value
int semInite(int semId, int value)
{
union semun semUnion;
semUnion.val = value; //set default semaphore
return semctl(semId, , SETVAL, semUnion);
} //delete semaphore
int semDelete(int semId)
{
union semun semUnion;
return semctl(semId, , IPC_RMID, semUnion);
} //semaphore P operation
int semP(int semId)
{
struct sembuf semBuf;
semBuf.sem_num = ; //indicate it is not semaphore array
semBuf.sem_op = -; //subtract one
semBuf.sem_flg = SEM_UNDO; return semop(semId, &semBuf, ); //return value
} //semaphore V operation
int semV(int semId)
{
struct sembuf semBuf;
semBuf.sem_num = ; //indicate it is not semaphore array
semBuf.sem_op = ; //subtract one
semBuf.sem_flg = SEM_UNDO; return semop(semId, &semBuf, ); //return value
}

111

两个信号量其实应该用信号量集的,因为它本来就是针对集合的,但是由于刚入门,为了易懂,就用两个。两个线程,创建的新线程当做消费者了。其中unix的几个信号量的函数看了半天,有点复杂,简单不准确来讲:

//获得一个信号量啦,第二个参数是想要创建的信号量个数,
//因为unix操作的是信号量集合,设为1不就一个信号量了嘛
//其他参数我不管了
int semget(key_t key, int num_sems, int sem_flags); //信号量集合的操作,这个可以用来实现P、V的 +1 -1 的功能
int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops); //信号量集合的控制,如初始化删除等
int semctl(int sem_id, int sem_num, int command, ...);

运行:




二:一个生产者、一个消费者、N个资源情况

  这里资源用是一个数组代替了。其实本质上和上面类似,每次只让生产者或消费者中的一个进入,进入后放到哪个地方或从哪个地方取就得用一个标志来说明了,其实也可以为每一资源加上信号量的。

  这里在生产者和消费者那里都设置了一个static的变量当做游标,指示下个资源放到哪个位置和下次从哪取资源。staitic变量用在这里很合适,因为只会初始化一次。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h> #include <x86_64-linux-gnu/sys/types.h>
#include <x86_64-linux-gnu/sys/ipc.h>
#include <x86_64-linux-gnu/sys/sem.h> #define N 5 int semInite(int semId, int value);
int semDelete(int semId);
int semP(int semId);
int semV(int semId); //declare a union to be used
union semun
{
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
unsigned short int *array; /* array for GETALL, SETALL */
struct seminfo *__buf; /* buffer for IPC_INFO */
}; //semaphore declare
static int semFullId;
static int semEmptyId;
static int srcArr[N]; //source definition //new thread as a consumer
void* child_thread(void* arg)
{
int ttt = ; while()
{
static int pToGet = ; //get source from the position
sleep(rand() % );
printf("child No.%d times wants to consume(get from index %d)...\n", ttt, pToGet); semP(semFullId); //
printf("child No.%d times start consuming.(get from index %d, data is %d)\n", ttt, pToGet, srcArr[pToGet]);
srcArr[pToGet] = ;
printf("child No.%d times end consuming. (get from index %d)\n\n", ttt++, pToGet);
pToGet = (pToGet + ) % N;
semV(semEmptyId); //
} return (void*);
} int main(void)
{
//create semaphore
semFullId = semget((key_t), , | IPC_CREAT);
semEmptyId = semget((key_t), , | IPC_CREAT);
semInite(semFullId, );
semInite(semEmptyId, N); //N source pthread_t pid;
pthread_create(&pid, NULL, child_thread, NULL); int tt = ;
while()
{
static int pToPut = ; //next position where source to be filled in
sleep(rand() % );
printf("parent No.%d times wants to produce(put in %d index)...\n", tt, pToPut); semP(semEmptyId); //
printf("parent No.%d times start producing.(put in %d index, original data is %d)\n", tt, pToPut, srcArr[pToPut]);
int temp = rand() % ;
srcArr[pToPut] = temp;
printf("parent No.%d times end producing.(put in %d index, now data is %d)\n", tt++, pToPut, srcArr[pToPut]);
pToPut = (pToPut + ) % N;
semV(semFullId); //
} semDelete(semFullId);
semDelete(semEmptyId);
return ;
} //set semaphore as default value
int semInite(int semId, int value)
{
union semun semUnion;
semUnion.val = value; //set default semaphore
return semctl(semId, , SETVAL, semUnion);
} //delete semaphore
int semDelete(int semId)
{
union semun semUnion;
return semctl(semId, , IPC_RMID, semUnion);
} //semaphore P operation
int semP(int semId)
{
struct sembuf semBuf;
semBuf.sem_num = ; //indicate it is not semaphore array
semBuf.sem_op = -; //subtract one
semBuf.sem_flg = SEM_UNDO; return semop(semId, &semBuf, ); //return value
} //semaphore V operation
int semV(int semId)
{
struct sembuf semBuf;
semBuf.sem_num = ; //indicate it is not semaphore array
semBuf.sem_op = ; //subtract one
semBuf.sem_flg = SEM_UNDO; return semop(semId, &semBuf, ); //return value
}

222

运行结果:




三:N个生产者,N个消费者,N个资源

  这种情况不仅生产者和消费者之间要通过上述的方式协调使用资源,而且生产者内部和消费者内部也要协调。定义四个信号量:

empty——表示缓冲区是否为空,初值为n。
full——表示缓冲区中是否为满,初值为0。
mutex1——生产者之间的互斥信号量,初值为1。
mutex2——消费者之间的互斥信号量,初值为1。

//生产者进程
P(mutex1)
P(empty)
生产数据并放进特定位置
V(full)
V(mutex1) //消费者进程
P(mutex2)
P(full)
消费数据
V(empty)
V(mutex2)

其实上面生产者或者消费者获取互斥量或信号量的顺序可以颠倒的,不会产生死锁。

  当然这个问题可以用其他更好的方式解决,我还得继续学习。

Linux 信号量 生产者消费者小例题的更多相关文章

  1. linux进程 生产者消费者

    #include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<string.h> # ...

  2. linux ptheard 生产者消费者

    ;     {           {          printf(         pthread_mutex_lock(&mutex);            != g_iBufSiz ...

  3. Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题

    Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_close sem_destroy sem_unlink sem_wait sem_post ...

  4. Linux线程编程之生产者消费者问题

    前言 本文基于顺序循环队列,给出Linux生产者/消费者问题的多线程示例,并讨论编程时需要注意的事项.文中涉及的代码运行环境如下: 本文假定读者已具备线程同步的基础知识. 一  顺序表循环队列 1.1 ...

  5. posix 匿名信号量与互斥锁 示例生产者--消费者问题

    一.posix 信号量 信号量的概念参见这里.前面也讲过system v 信号量,现在来说说posix 信号量. system v 信号量只能用于进程间同步,而posix 信号量除了可以进程间同步,还 ...

  6. Linux线程编程之生产者消费者问题【转】

    转自:http://www.cnblogs.com/clover-toeic/p/4029269.html 前言 本文基于顺序循环队列,给出Linux生产者/消费者问题的多线程示例,并讨论编程时需要注 ...

  7. Linux 进程间通信(包含一个经典的生产者消费者实例代码)

    前言:编写多进程程序时,有时不可避免的需要在多个进程之间传递数据,我们知道,进程的用户的地址空间是独立,父进程中对数据的修改并不会反映到子进程中,但内核是共享的,大多数进程间通信方式都是在内核中建立一 ...

  8. 进程同步控制(锁,信号量,事件), 进程通讯(队列和管道,生产者消费者模型) 数据共享(进程池和mutiprocess.Pool模块)

    参考博客 https://www.cnblogs.com/xiao987334176/p/9025072.html#autoid-1-1-0 进程同步(multiprocess.Lock.Semaph ...

  9. python 全栈开发,Day39(进程同步控制(锁,信号量,事件),进程间通信(队列,生产者消费者模型))

    昨日内容回顾 python中启动子进程并发编程并发 :多段程序看起来是同时运行的ftp 网盘不支持并发socketserver 多进程 并发异步 两个进程 分别做不同的事情 创建新进程join :阻塞 ...

随机推荐

  1. [Ramda] Compose and Curry

    Curry: The idea of Curry is to spreate the data from the function. Using Curry to define the functio ...

  2. LeetCode: Validata Binary Search Tree

    LeetCode: Validata Binary Search Tree Given a binary tree, determine if it is a valid binary search ...

  3. 分布式ActiveMQ集群--转载

    原文地址:http://shensy.iteye.com/blog/1752529 回顾总结前一段时间学习的ActiveMQ分布式集群相关的知识,分享出来希望对看到的人有所帮助. 一.分布式Activ ...

  4. mysql --The MEMORY Storage Engine--官方文档

    原文地址:http://dev.mysql.com/doc/refman/5.7/en/memory-storage-engine.html The MEMORY storage engine (fo ...

  5. Windows 7中使用Eclipse 使用CDT and WinGW 开发C/C++(转载)

    以前使用visual studio 2010编写C/C++,后来接触了Eclipse后,据说eclipse也可以编写C/C++,以前觉得Visual studio 2010还蛮不错的,也没有多大好奇心 ...

  6. Debian7.7 wheezy 中源码安装emacs24

    我用的是ARM版本,竟然没有最新的emacs 24,很多第三方插件不能用,果断重新编译个1.追加软件源 deb-src http://ftp.cn.debian.org/debian/ wheezy ...

  7. PHP.1-网站开发概述

    网站开发概述 网站开发从本质来说,就是软件开发 1.B/S软件体系统结构 BS:浏览器与服务器的结构[降低客户端电脑的负荷,减轻维护成本,对CS的改进,可随时随地进行业务处理] #对美工要求比较高,注 ...

  8. BootStrap2学习日记3--响应式布局实用类

    BootStrap2中常用的响应式布局类如: visible-phone     仅在 手机平台显示 visible-tablet      仅在 平板电脑显示 visible-desktop   仅 ...

  9. struts2.1笔记06:struts2开发环境的搭建实际操作出现的问题

    1.我根据新建一个struts工程之后,启动报错,如下: 六月 29, 2015 3:08:18 下午 org.apache.catalina.core.AprLifecycleListener in ...

  10. 给jdk写注释系列之jdk1.6容器(10)-Stack&Vector源码解析

    前面我们已经接触过几种数据结构了,有数组.链表.Hash表.红黑树(二叉查询树),今天再来看另外一种数据结构:栈.      什么是栈呢,我就不找它具体的定义了,直接举个例子,栈就相当于一个很窄的木桶 ...