linux 生产者 linux多线程生产者与消费者
老铁们,大家好,相信还有很多朋友对于linux 生产者和linux多线程生产者与消费者的相关问题不太懂,没关系,今天就由我来为大家分享分享linux 生产者以及linux多线程生产者与消费者的问题,文章篇幅可能偏长,希望可以帮助到大家,下面一起来看看吧!
Linux 多线程编程(二)2019-08-10
三种专门用于线程同步的机制:POSIX信号量,互斥量和条件变量.
在Linux上信号量API有两组,一组是System V IPC信号量,即PV操作,另外就是POSIX信号量,POSIX信号量的名字都是以sem_开头.
phshared参数指定信号量的类型,若其值为0,就表示这个信号量是当前进程的局部信号量,否则该信号量可以在多个进程之间共享.value值指定信号量的初始值,一般与下面的sem_wait函数相对应.
其中比较重要的函数sem_wait函数会以原子操作的方式将信号量的值减一,如果信号量的值为零,则sem_wait将会阻塞,信号量的值可以在sem_init函数中的value初始化;sem_trywait函数是sem_wait的非阻塞版本;sem_post函数将以原子的操作对信号量加一,当信号量的值大于0时,其他正在调用sem_wait等待信号量的线程将被唤醒.
这些函数成功时返回0,失败则返回-1并设置errno.
生产者消费者模型:
生产者对应一个信号量:sem_t producer;
消费者对应一个信号量:sem_t customer;
sem_init(&producer,2)----生产者拥有资源,可以工作;
sem_init(&customer,0)----消费者没有资源,阻塞;
在访问公共资源前对互斥量设置(加锁),确保同一时间只有一个线程访问数据,在访问完成后再释放(解锁)互斥量.
互斥锁的运行方式:串行访问共享资源;
信号量的运行方式:并行访问共享资源;
互斥量用pthread_mutex_t数据类型表示,在使用互斥量之前,必须使用pthread_mutex_init函数对它进行初始化,注意,使用完毕后需调用pthread_mutex_destroy.
pthread_mutex_init用于初始化互斥锁,mutexattr用于指定互斥锁的属性,若为NULL,则表示默认属性。除了用这个函数初始化互斥所外,还可以用如下方式初始化:pthread_mutex_t mutex= PTHREAD_MUTEX_INITIALIZER。
pthread_mutex_destroy用于销毁互斥锁,以释放占用的内核资源,销毁一个已经加锁的互斥锁将导致不可预期的后果。
pthread_mutex_lock以原子操作给一个互斥锁加锁。如果目标互斥锁已经被加锁,则pthread_mutex_lock则被阻塞,直到该互斥锁占有者把它给解锁.
pthread_mutex_trylock和pthread_mutex_lock类似,不过它始终立即返回,而不论被操作的互斥锁是否加锁,是pthread_mutex_lock的非阻塞版本.当目标互斥锁未被加锁时,pthread_mutex_trylock进行加锁操作;否则将返回EBUSY错误码。注意:这里讨论的pthread_mutex_lock和pthread_mutex_trylock是针对普通锁而言的,对于其他类型的锁,这两个加锁函数会有不同的行为.
pthread_mutex_unlock以原子操作方式给一个互斥锁进行解锁操作。如果此时有其他线程正在等待这个互斥锁,则这些线程中的一个将获得它.
三个打印机轮流打印:
输出结果:
如果说互斥锁是用于同步线程对共享数据的访问的话,那么条件变量就是用于在线程之间同步共享数据的值.条件变量提供了一种线程之间通信的机制:当某个共享数据达到某个值时,唤醒等待这个共享数据的线程.
条件变量会在条件不满足的情况下阻塞线程.且条件变量和互斥量一起使用,允许线程以无竞争的方式等待特定的条件发生.
其中pthread_cond_broadcast函数以广播的形式唤醒所有等待目标条件变量的线程,pthread_cond_signal函数用于唤醒一个等待目标条件变量线程.但有时候我们可能需要唤醒一个固定的线程,可以通过间接的方法实现:定义一个能够唯一标识目标线程的全局变量,在唤醒等待条件变量的线程前先设置该变量为目标线程,然后采用广播的方式唤醒所有等待的线程,这些线程被唤醒之后都检查该变量以判断是否是自己.
采用条件变量+互斥锁实现生产者消费者模型:
运行结果:
阻塞队列+生产者消费者
运行结果:
Linux中rpm和yum命令的异同点是什么
Linux中rpm和yum命令有相似之处但是也有根本区别,具体异同点如下。
一、相同点
rpm和yum命令都是软件包管理器,是用于互联网下载包的打包及安装工具。它们的操作系统都是FedoraLinux。
二、不同点
1、安装程序不同
RPM文件在Linux系统中的安装最为简便。以著名的图像处理软件XV为例,其RPM包xv-3.10a-13.i386.rpm可以在该程序的主页中下载取得。如果连网速度足够快,可以直接从网络上安装应用软件,只需要在软件的文件名前加上适当的URL路径。作为一个软件包管理工具,RPM管理着系统已安装的所有RPM程序组件的资料,因此可以使用RPM来卸载相关的应用程序。
可供Yum下载的软件包包括Fedora本身的软件包以及源自rpmfusion和rpm.的Fedora Extras,全部是由Linux社区维护的,并且基本是自由软件。所有的包都有一个独立的PGP签名,主要是为了用户的系统安全。而对于Fedora core 4.0的用户,rpm.的签名是自动导入并安装的。
2、两者优点不同
Yum是rpm的前端程序,主要目的是设计用来自动解决rpm的依赖关系。它可以自动解决依赖关系,也可以对rpm进行分组,基于组进行安装操作。引入仓库概念,支持多个仓库并且配置简单。 yum仓库用来存放所有的现有的.rpm包,当使用yum安装一个rpm包时,需要依赖关系,会自动在仓库中查找依赖软件并安装。仓库可以是本地的,也可以是HTTP、FTP、nfs形式使用的统一的网络仓库。
RPM是Red Hat公司随Redhat Linux推出了一个软件包管理器,通过它能够更加轻松容易地实现软件的安装。RPM通过将代码基于特定平台系统编译为可执行文件,并保存依赖关系,来简化开源软件的安装管理。针对不同的系统设定不同的安装包。并且它的组件查询功能和验证功能十分出色。
3、两者硬件描述不同
RPM是高通专用的硬件引擎,用于管理共享的SoC(系统级芯片)相关资源,其中包括总线,时钟,电源轨等。RPM的目标是满足SoC的操作和性能要求的同时实现最大的功率节省。RPM接受多个RPM主控的资源请求。仲裁和聚合请求,并配置共享资源。RPM的主控方有应用处理器,调制解调处理器,以及一些硬件加速器。
RPM包含内部逻辑,用来聚合和仲裁不同RPM主控方的请求。它同PMIC,总线仲裁模块,以及时钟控制模块都有接口,以便配置共享资源。
而yum是一个在Fedora和RedHat以及CentOS中的Shell前端软件包管理器。基于RPM包管理,能够从指定的服务器自动下载RPM包并且安装,可以自动处理依赖性关系,并且一次安装所有依赖的软件包,无须繁琐地一次次下载、安装。
扩展资料
软件包的构成和分类
一、构成
可分为应用软件包和系统软件包两大类。应用软件包与特定的应用领域有关,又可分为通用包及专用包两类。通用软件包根据社会的一些共同需求开发,专用软件包则是生产者根据用户的具体需求定制的,可以为适合其特殊需要进行修改或变更。
软件包既可以是源代码形式,也可以是目标码形式。用户手册和指南等文档是软件包的重要组成部分。此外,软件包的维护及技术支持也是非常必要的。
软件包在系统管理中,软件包的管理是最重要的,是系统管理的基础的基础;只有学会软件包的管理才能谈得上其它的应用。管理软件包需要了解文档格式、更新软件包、查询相对的文档,以及熟悉几个常用的软件包管理工具,比如system-cofig-packages、yum、ppapt等。
二、分类
分成Linux、BSD系统和Windows系统
在Linux、BSD系统中,软件包主要以两种形式出现:二进制包以及源代码包。主要的二进制包格式有rpm、deb、Autopackage。源代码包则主要适用于自由软件的安装,用户需要自己编译它们。对于Windows系统,在Windows中,软件包大多数以安装程序的方式出现,可以将软件安装在制定的目录中,也有直接使用压缩工具打包的,解压缩之后便可运行。
参考资料来源:百度百科-RPM(RPM软件包管理器)
参考资料来源:百度百科-yum
求助,关于linux的线程同步问题
【Linux多线程】三个经典同步问题
标签:多线程同步生产者与消费者写者与读者
目录(?)[+]
在了解了《同步与互斥的区别》之后,我们来看看几个经典的线程同步的例子。相信通过具体场景可以让我们学会分析和解决这类线程同步的问题,以便以后应用在实际的项目中。
一、生产者-消费者问题
问题描述:
一组生产者进程和一组消费者进程共享一个初始为空、大小为 n的缓冲区,只有缓冲区没满时,生产者才能把消息放入到缓冲区,否则必须等待;只有缓冲区不空时,消费者才能从中取出消息,否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入消息,或者一个消费者从中取出消息。
分析:
关系分析:生产者和消费者对缓冲区互斥访问是互斥关系,同时生产者和消费者又是一个相互协作的关系,只有生产者生产之后,消费者才能消费,它们也是同步关系。
整理思路:这里比较简单,只有生产者和消费者两个进程,且这两个进程存在着互斥关系和同步关系。那么需要解决的是互斥和同步的PV操作的位置。
信号量设置:信号量mutex作为互斥信号量,用于控制互斥访问缓冲池,初值为1;信号量full用于记录当前缓冲池中“满”缓冲区数,初值为 0;信号量empty用于记录当前缓冲池中“空”缓冲区数,初值为n。
代码示例:(semaphore类的封装见下文)
#include<iostream>
#include<unistd.h>// sleep
#include<pthread.h>
#include"semaphore.h"
using namespace std;
#define N 5
semaphore mutex("/", 1);//临界区互斥信号量
semaphore empty("/home", N);//记录空缓冲区数,初值为N
semaphore full("/home/songlee",0);//记录满缓冲区数,初值为0
int buffer[N];//缓冲区,大小为N
int i=0;
int j=0;
void* producer(void* arg)
{
empty.P();// empty减1
mutex.P();
buffer[i]= 10+ rand()% 90;
printf("Producer%d write Buffer[%d]:%d\n",arg,i+1,buffer[i]);
i=(i+1)% N;
mutex.V();
full.V();// full加1
}
void* consumer(void* arg)
{
full.P();// full减1
mutex.P();
printf("\033[1;31m");
printf("Consumer%d read Buffer[%d]:%d\n",arg,j+1,buffer[j]);
printf("\033[0m");
j=(j+1)% N;
mutex.V();
empty.V();// empty加1
}
int main()
{
pthread_t id[10];
//开10个生产者线程,10个消费者线程
for(int k=0; k<10;++k)
pthread_create(&id[k], NULL, producer,(void*)(k+1));
for(int k=0; k<10;++k)
pthread_create(&id[k], NULL, consumer,(void*)(k+1));
sleep(1);
return 0;
}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455561234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
编译运行输出结果:
Producer 1 write Buffer[1]: 83
Producer 2 write Buffer[2]: 26
Producer 3 write Buffer[3]: 37
Producer 5 write Buffer[4]: 35
Producer 4 write Buffer[5]: 33
Consumer 1 read Buffer[1]: 83
Producer 6 write Buffer[1]: 35
Consumer 2 read Buffer[2]: 26
Consumer 3 read Buffer[3]: 37
Consumer 4 read Buffer[4]: 35
Consumer 5 read Buffer[5]: 33
Consumer 6 read Buffer[1]: 35
Producer 7 write Buffer[2]: 56
Producer 8 write Buffer[3]: 22
Producer 10 write Buffer[4]: 79
Consumer 9 read Buffer[2]: 56
Consumer 10 read Buffer[3]: 22
Producer 9 write Buffer[5]: 11
Consumer 7 read Buffer[4]: 79
Consumer 8 read Buffer[5]: 1112345678910111213141516171819201234567891011121314151617181920
二、读者-写者问题
问题描述:
有读者和写者两组并发线程,共享一个文件,当两个或以上的读线程同时访问共享数据时不会产生副作用,但若某个写线程和其他线程(读线程或写线程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:
允许多个读者可以同时对文件执行读操作;
只允许一个写者往文件中写信息;
任一写者在完成写操作之前不允许其他读者或写者工作;
写者执行写操作前,应让已有的读者和写者全部退出。
分析:
关系分析:由题目分析可知,读者和写者是互斥的,写者和写者也是互斥的,而读者和读者不存在互斥问题。
整理思路:写者是比较简单的,它与任何线程互斥,用互斥信号量的 PV操作即可解决。读者的问题比较复杂,它必须实现与写者的互斥,多个读者还可以同时读。所以,在这里用到了一个计数器,用它来判断当前是否有读者读文件。当有读者的时候写者是无法写文件的,此时读者会一直占用文件,当没有读者的时候写者才可以写文件。同时,不同的读者对计数器的访问也应该是互斥的。
信号量设置:首先设置一个计数器count,用来记录当前的读者数量,初值为0;设置互斥信号量mutex,用于保护更新 count变量时的互斥;设置互斥信号量rw用于保证读者和写者的互斥访问。
代码示例:
#include<iostream>
#include<unistd.h>// sleep
#include<pthread.h>
#include"semaphore.h"
using namespace std;
int count= 0;//记录当前的读者数量
semaphore mutex("/",1);//用于保护更新count变量时的互斥
semaphore rw("/home",1);//用于保证读者和写者的互斥
void* writer(void* arg)
{
rw.P();//互斥访问共享文件
printf(" Writer%d start writing...\n", arg);
sleep(1);
printf(" Writer%d finish writing...\n", arg);
rw.V();//释放共享文件
}
void* reader(void* arg)
{
mutex.P();//互斥访问count变量
if(count== 0)//当第一个读线程读文件时
rw.P();//阻止写线程写
++count;//读者计数器加1
mutex.V();//释放count变量
printf("Reader%d start reading...\n", arg);
sleep(1);
printf("Reader%d finish reading...\n", arg);
mutex.P();//互斥访问count变量
--count;//读者计数器减1
if(count== 0)//当最后一个读线程读完文件
rw.V();//允许写线程写
mutex.V();//释放count变量
}
int main()
{
pthread_t id[8];//开6个读线程,2个写线程
pthread_create(&id[0], NULL, reader,(void*)1);
pthread_create(&id[1], NULL, reader,(void*)2);
pthread_create(&id[2], NULL, writer,(void*)1);
pthread_create(&id[3], NULL, writer,(void*)2);
pthread_create(&id[4], NULL, reader,(void*)3);
pthread_create(&id[5], NULL,reader,(void*)4);
sleep(2);
pthread_create(&id[6], NULL, reader,(void*)5);
pthread_create(&id[7], NULL,reader,(void*)6);
sleep(4);
return 0;
}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
编译运行的结果如下:
Reader 2 start reading...
Reader 1 start reading...
Reader 3 start reading...
Reader 4 start reading...
Reader 1 finish reading...
Reader 2 finish reading...
Reader 3 finish reading...
Reader 4 finish reading...
Writer 1 start writing...
Writer 1 finish writing...
Writer 2 start writing...
Writer 2 finish writing...
Reader 5 start reading...
Reader 6 start reading...
Reader 5 finish reading...
Reader 6 finish reading...1234567891011121314151612345678910111213141516
三、哲学家进餐问题
问题描述:
一张圆桌上坐着 5名哲学家,桌子上每两个哲学家之间摆了一根筷子,桌子的中间是一碗米饭,如图所示:
哲学家们倾注毕生精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿的时候,才试图拿起左、右两根筷子(一根一根拿起)。如果筷子已在他人手上,则需等待。饥饿的哲学家只有同时拿到了两根筷子才可以开始进餐,当进餐完毕后,放下筷子继续思考。
分析:
关系分析:5名哲学家与左右邻居对其中间筷子的访问是互斥关系。
整理思路:显然这里有 5个线程,那么要如何让一个哲学家拿到左右两个筷子而不造成死锁或饥饿现象?解决方法有两个,一个是让他们同时拿两个筷子;二是对每个哲学家的动作制定规则,避免饥饿或死锁现象的发生。
信号量设置:定义互斥信号量数组chopstick[5]={1,1,1,1,1}用于对 5根筷子的互斥访问。
示例代码: