-posix信号量信号量

是打开一个有名的信号量

sem_init是打开一个无名的信号量,无名信号量的销毁用sem_destroy

sem_wait和sem_post是对信号量进行pv操作,既可以使用在有名的信号量也可以使用在无名的信号量

无名信号量是否意味着它不能够用于不同进程的多个线程之间的通信了

如果sem_init是非零的参数,那么这个无名的信号量可以用于不同进程间的多个线程之间的通信,前提条件是这个信号量的对象必须存储在共享内存区才可以。

上面这是互斥锁是无名的互斥锁,同样也可以可以用于不同进程间的多个线程之间的通信,前提条件是这个信号量的对象必须存储在共享内存区才可以。

下面我们使用互斥锁来解决生产者消费者的问题

生产者消费者问题是这样描述的,有一个缓冲区,是一个有大小的缓冲区,对于生产者来说,首先判断当前缓冲区是否满了,满了就阻塞不再生产,我们使用信号量来实现

使用信号量p(sem_full)的信号量来实现,初始化的值就是缓冲区的大小,一旦生产了一个产品sem_full的计数值值减一,一旦我们生成了产品,缓冲区不再是空的状态,我们使用一个

v(sem_empty)的信号量,用来告诉消费者可以来消费产品了,我们在生成产品的时候,由于生产者可能是多个,我们需要有一个互斥锁来包含缓冲区。

对于消费者,消费者也存在多个,首先判断当前缓冲区是否是空的,如果是空的就不能消费产品,需要等待生产者给消费者一个信号,消费者新建一个p(sem_empty)信号,使得信号量加一,这样消费者就可以消费产品了,

一旦消费者消费了一个产品,就会使得缓冲区的大小加一v(sem_full)这样的信号量,对于缓冲区,多个消费者也需要互斥

对于初始化,一开始只能生产产品,不能消费产品,假设缓冲区的大小是10,sem_full是10,sem_empty为0

下面我们通过代码来理解下面的问题:

信号量是在多线程环境中共享资源的计数器

sem_wait() 减小(锁定)由sem指定的信号量的值.如果信号量的值比0大,
  那么进行减一的操作,函数立即返回.
  如果信号量当前为0值,那么调用就会一直阻塞直到或者是信号量变得可以进行减一的操作
  (例如,信号量的值比0大),或者是信号处理程序中断调用

当前初始化的sem_full的值是10,减一之后函数会立即返回不会阻塞

sem_wait   sem_post

信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:  

extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));  

sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。  

函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。  

函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。  

函数sem_destroy(sem_t *sem)用来释放信号量sem。 

信号量用sem_init函数创建的,下面是它的说明:
  #include<semaphore.h>
 int sem_init (sem_t *sem, int pshared, unsigned int value);

生产完一个产品之后sem_post(&sem_empty)是的sem_empty的信号量的值加一

我们来看程序的代码:

#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
#define CONSUMERS_COUNT 1
#define PRODUCERS_COUNT 1
#define BUFFSIZE 10
int g_buffer[BUFFSIZE];
unsigned short in = 0;
unsigned short out = 0;
unsigned short produce_id = 0;
unsigned short consume_id = 0;
sem_t g_sem_full;
sem_t g_sem_empty;
pthread_mutex_t g_mutex;
pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT];
void *consume(void *arg)
{
int i;
int num = (int)arg;
while (1)
{
printf("%d wait buffer not empty\n", num);
sem_wait(&g_sem_empty);
pthread_mutex_lock(&g_mutex);
for (i = 0; i < BUFFSIZE; i++)
{
printf("%02d ", i);
if (g_buffer[i] == -1)
printf("%s", "null");
else
printf("%d", g_buffer[i]);
if (i == out)
printf("\t<--consume");
printf("\n");
}
consume_id = g_buffer[out];
printf("%d begin consume product %d\n", num, consume_id);
g_buffer[out] = -1;
out = (out + 1) % BUFFSIZE;
printf("%d end consume product %d\n", num, consume_id);
pthread_mutex_unlock(&g_mutex);
sem_post(&g_sem_full);
sleep(1);
}
return NULL;
}
void *produce(void *arg)
{
int num = (int)arg;
int i;
while (1)
{
printf("%d wait buffer not full\n", num);
sem_wait(&g_sem_full);
pthread_mutex_lock(&g_mutex);
for (i = 0; i < BUFFSIZE; i++)
{
printf("%02d ", i);
if (g_buffer[i] == -1)
printf("%s", "null");
else
printf("%d", g_buffer[i]);
if (i == in)
printf("\t<--produce");
printf("\n");
}
printf("%d begin produce product %d\n", num, produce_id);
g_buffer[in] = produce_id;
in = (in + 1) % BUFFSIZE;
printf("%d end produce product %d\n", num, produce_id++);
pthread_mutex_unlock(&g_mutex);
sem_post(&g_sem_empty);
sleep(5);
}
return NULL;
}
int main(void)
{
int i;
for (i = 0; i < BUFFSIZE; i++)
g_buffer[i] = -1;
sem_init(&g_sem_full, 0, BUFFSIZE);
sem_init(&g_sem_empty, 0, 0);
pthread_mutex_init(&g_mutex, NULL); for (i = 0; i < CONSUMERS_COUNT; i++)
pthread_create(&g_thread[i], NULL, consume, (void *)i);
for (i = 0; i < PRODUCERS_COUNT; i++)
pthread_create(&g_thread[CONSUMERS_COUNT + i], NULL, produce, (void *)i);
for (i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; i++)
pthread_join(g_thread[i], NULL);
sem_destroy(&g_sem_full);
sem_destroy(&g_sem_empty);
pthread_mutex_destroy(&g_mutex);
return 0;
}

编译的时候需要加上gcc proudct.c -o product -lpthread

可以查看博客:

http://blog.csdn.net/nk_test/article/details/50449704

linux网络编程-posix信号量与互斥锁(39)的更多相关文章

  1. linux网络编程之posix信号量与互斥锁

    继上次学习了posix线程之后,这次来讨论一下posix信号量与互斥锁相关的知识: 跟posix消息队列,共享内存的打开,关闭,删除操作一样,不过,上面的函数是对有名信号量进行操作,通过man帮助可以 ...

  2. POSIX信号量与互斥锁实现生产者消费者模型

    posix信号量 Link with -lpthread. sem_t *sem_open(const char *name, int oflag);//打开POSIX信号量 sem_t *sem_o ...

  3. Linux——临界段,信号量,互斥锁,自旋锁,原子操作

    一. linux为什么需要临界段,信号量,互斥锁,自旋锁,原子操作? 1.1. linux内核后期版本是支持多核CPU以及抢占式调度.这里就存在一个并发,竞争状态(简称竟态). 1.2. 竞态条件 发 ...

  4. 第三十九章 POSIX信号量与互斥锁

    POSIX信号量相关函数 sem_open 功能: initialize and open a named semaphore 原型: sem_t *sem_open(const char *name ...

  5. posix信号量与互斥锁

    1.简介 POSIX信号量是一个sem_t 类型的变量,但POSIX 有两种信号量的实现机制:无名信号量和命名信号量.无名信号量可以用在共享内存的情况下, 比如实现进程中各个线程之间的互斥和同步.命名 ...

  6. linux网络编程-posix条件变量(40)

    举一个列子来说明条件变量: 假设有两个线程同时访问全局变量n,初始化值是0, 一个线程进入临界区,进行互斥操作,线程当n大于0的时候才执行下面的操作,如果n不大于0,该线程就一直等待. 另外一个线程也 ...

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

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

  8. 漫画|Linux 并发、竞态、互斥锁、自旋锁、信号量都是什么鬼?(转)

    知乎链接:https://zhuanlan.zhihu.com/p/57354304 1. 锁的由来? 学习linux的时候,肯定会遇到各种和锁相关的知识,有时候自己学好了一点,感觉半桶水的自己已经可 ...

  9. linux网络编程基础--(转自网络)

    转自 http://www.cnblogs.com/MyLove-Summer/p/5215287.html Linux下的网络编程指的是socket套接字编程,入门比较简单. 1. socket套接 ...

随机推荐

  1. 09 . Python3之常用模块

    模块的定义与分类 模块是什么? 一个函数封装一个功能,你使用的软件可能就是由n多个函数组成的(先备考虑面向对象).比如抖音这个软件,不可能将所有程序都写入一个文件,所以咱们应该将文件划分,这样其组织结 ...

  2. 【译】Welcome to C# 9.0

    C# 9.0正在形成,我想分享我们对添加到该语言下个版本的一些主要功能的看法.对于每个新版本的 C#,我们努力使常见的编码方案更加清晰和简单,C# 9.0 也不例外.这次的一个特别重点是支持数据形状的 ...

  3. 50个SQL语句(MySQL版) 问题十三

    --------------------------表结构-------------------------- student(StuId,StuName,StuAge,StuSex) 学生表 tea ...

  4. vue 使用 elementUI 和 antd 的细微差别

    Checkbox a-checkbox 没有value属性,绑定用checked Collapse 使用折叠面板的时候,antd 的层级关系是 .ant-collapse >.ant-colla ...

  5. Chisel3 - Tutorial - Functionality

    https://mp.weixin.qq.com/s/3hDzpJiANdwp07hO03psyA   演示使用函数进行代码复用的方法.   参考链接: https://github.com/ucb- ...

  6. Java实现 LeetCode 232 用栈实现队列

    232. 用栈实现队列 使用栈实现队列的下列操作: push(x) – 将一个元素放入队列的尾部. pop() – 从队列首部移除元素. peek() – 返回队列首部的元素. empty() – 返 ...

  7. Java实现 蓝桥杯VIP 算法训练 字符串编辑

    算法训练 字符串编辑 时间限制:1.0s 内存限制:512.0MB 问题描述 从键盘输入一个字符串(长度<=40个字符),并以字符 '.' 结束.编辑功能有: 1 D:删除一个字符,命令的方式为 ...

  8. Java 实现 蓝桥杯 历届试题 分糖果

    问题描述 有n个小朋友围坐成一圈.老师给每个小朋友随机发偶数个糖果,然后进行下面的游戏: 每个小朋友都把自己的糖果分一半给左手边的孩子. 一轮分糖后,拥有奇数颗糖的孩子由老师补给1个糖果,从而变成偶数 ...

  9. 【CSS】常用色值

    常用颜色: 嫣红(red):#e54d42 桔橙(orange):#f37b1d 明黄(yellow):#fbbd08 橄榄(olive):#8dc63f 森绿(green):#39b54a 天青(c ...

  10. BFART算法

    参考:https://zhuanlan.zhihu.com/p/31498036 https://www.jianshu.com/p/83bb10ad1d32