linux网络编程-posix信号量与互斥锁(39)
-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
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)的更多相关文章
- linux网络编程之posix信号量与互斥锁
继上次学习了posix线程之后,这次来讨论一下posix信号量与互斥锁相关的知识: 跟posix消息队列,共享内存的打开,关闭,删除操作一样,不过,上面的函数是对有名信号量进行操作,通过man帮助可以 ...
- POSIX信号量与互斥锁实现生产者消费者模型
posix信号量 Link with -lpthread. sem_t *sem_open(const char *name, int oflag);//打开POSIX信号量 sem_t *sem_o ...
- Linux——临界段,信号量,互斥锁,自旋锁,原子操作
一. linux为什么需要临界段,信号量,互斥锁,自旋锁,原子操作? 1.1. linux内核后期版本是支持多核CPU以及抢占式调度.这里就存在一个并发,竞争状态(简称竟态). 1.2. 竞态条件 发 ...
- 第三十九章 POSIX信号量与互斥锁
POSIX信号量相关函数 sem_open 功能: initialize and open a named semaphore 原型: sem_t *sem_open(const char *name ...
- posix信号量与互斥锁
1.简介 POSIX信号量是一个sem_t 类型的变量,但POSIX 有两种信号量的实现机制:无名信号量和命名信号量.无名信号量可以用在共享内存的情况下, 比如实现进程中各个线程之间的互斥和同步.命名 ...
- linux网络编程-posix条件变量(40)
举一个列子来说明条件变量: 假设有两个线程同时访问全局变量n,初始化值是0, 一个线程进入临界区,进行互斥操作,线程当n大于0的时候才执行下面的操作,如果n不大于0,该线程就一直等待. 另外一个线程也 ...
- posix 匿名信号量与互斥锁 示例生产者--消费者问题
一.posix 信号量 信号量的概念参见这里.前面也讲过system v 信号量,现在来说说posix 信号量. system v 信号量只能用于进程间同步,而posix 信号量除了可以进程间同步,还 ...
- 漫画|Linux 并发、竞态、互斥锁、自旋锁、信号量都是什么鬼?(转)
知乎链接:https://zhuanlan.zhihu.com/p/57354304 1. 锁的由来? 学习linux的时候,肯定会遇到各种和锁相关的知识,有时候自己学好了一点,感觉半桶水的自己已经可 ...
- linux网络编程基础--(转自网络)
转自 http://www.cnblogs.com/MyLove-Summer/p/5215287.html Linux下的网络编程指的是socket套接字编程,入门比较简单. 1. socket套接 ...
随机推荐
- Zabbix漏洞学习
Zabbix介绍 zabbix([`zæbiks])是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案. zabbix能监视各种网络参数,保证服务器系统的安全运营:并提供灵 ...
- Java实现 蓝桥杯 算法提高 字符串匹配
试题 算法提高 字符串匹配 问题描述 给出一个字符串和多行文字,在这些文字中找到字符串出现的那些行.你的程序还需支持大小写敏感选项:当选项打开时,表示同一个字母的大写和小写看作不同的字符:当选项关闭时 ...
- (Java实现) 洛谷 P1028 数的计算
题目描述 我们要求找出具有下列性质数的个数(包含输入的自然数nn): 先输入一个自然数n(n≤1000),然后对此自然数按照如下方法进行处理: 不作任何处理; 在它的左边加上一个自然数,但该自然数不能 ...
- Java实现蓝桥杯模拟约数的个数
问题描述 1200000有多少个约数(只计算正约数). 答案提交 这是一道结果填空的题,你只需要算出结果后提交即可.本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分. pac ...
- Java实现 蓝桥杯 生命游戏
标题:生命游戏 康威生命游戏是英国数学家约翰·何顿·康威在1970年发明的细胞自动机. 这个游戏在一个无限大的2D网格上进行. 初始时,每个小方格中居住着一个活着或死了的细胞. 下一时刻每个细胞的状态 ...
- SQK Server实现 LeetCode 175 组合两个表
175. 组合两个表 SQL架构 表1: Person +-------------+---------+ | 列名 | 类型 | +-------------+---------+ | Person ...
- Java实现 洛谷 P1980 计数问题
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = ...
- Java实现 蓝桥杯 历届试题 波动数列
问题描述 观察这个数列: 1 3 0 2 -1 1 -2 - 这个数列中后一项总是比前一项增加2或者减少3. 栋栋对这种数列很好奇,他想知道长度为 n 和为 s 而且后一项总是比前一项增加a或者减少b ...
- Linux文件处理命令 ls 详解
Linux系统的应用场景最多的就是用作服务器的系统了,简洁,安全,高效,一般我们服务器端不会安装Linux的图形化界面,虽然现在一些Linux发行版的图形界面也很漂亮,但是,服务器最主要的是高效.所以 ...
- FPGA之SPI SD卡读操作
这几天在FPGA调试与SD通信,读SD卡里的图片,之前接触32时没有去研究过SD卡,不太熟悉操作流程,在网上找了很多资料,也看了几个32开发板的资料,但大多数都讲得不是特别清楚,只能瞎操作了一番,在别 ...