Linux信号量机制实现读者写者问题

Linux信号量机制实现读者写者问题,第1张

生产者/消费者问题在windows2000下的实现

一、问题描述

生产者-消费者问题是一个经典的进程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。本作业要求设计在同一个进程地址空间内执行的两个线程生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。

二、实现代码

#include <windows.h>

#include <iostream>

const unsigned short SIZE_OF_BUFFER = 10//缓冲区长度

unsigned short ProductID = 0 //产品号

unsigned short ConsumeID = 0 //将被消耗的产品号

unsigned short in = 0 //产品进缓冲区时的缓冲区下标

unsigned short out = 0 //产品出缓冲区时的缓冲区下标

int g_buffer[SIZE_OF_BUFFER] //缓冲区是个循环队列

bool g_continue = true //控制程序结束

HANDLE g_hMutex //用于线程间的互斥

HANDLE g_hFullSemaphore//当缓冲区满时迫使生产者等待

HANDLE g_hEmptySemaphore//当缓冲区空时迫使消费者等待

DWORD WINAPI Producer(LPVOID) //生产者线程

DWORD WINAPI Consumer(LPVOID) //消费者线程

int main()

{

//创建各个互斥信号

g_hMutex = CreateMutex(NULL,FALSE,NULL)

g_hEmptySemaphore = CreateSemaphore(NULL,0,SIZE_OF_BUFFER-1,NULL)

//调整下面的数值,可以发现,当生产者个数多于消费者个数时,

//生产速度快,生产者经常等待消费者;反之,消费者经常等待

const unsigned short PRODUCERS_COUNT = 3 //生产者的个数

const unsigned short CONSUMERS_COUNT = 1 //消费者的个数

//总的线程数

const unsigned short THREADS_COUNT = PRODUCERS_COUNT+CONSUMERS_COUNT

DWORD producerID[CONSUMERS_COUNT]//生产者线程的标识符

DWORD consumerID[THREADS_COUNT]//消费者线程的标识符

//创建生产者线程

for (int i=0i<PRODUCERS_COUNT++i){

hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i])

if (hThreads[i]==NULL) return -1

}

//创建消费者线程

for (int i=0i<CONSUMERS_COUNT++i){

hThreads[PRODUCERS_COUNT+i]=CreateThread(NULL,0,Consumer,NULL,0,&consumerID[i])

if (hThreads[i]==NULL) return -1

}

while(g_continue){

if(getchar()){ //按回车后终止程序运行

g_continue = false

}

}

return 0

}

//生产一个产品。简单模拟了一下,仅输出新产品的ID号

void Produce()

{

std::cerr <<"Producing " <<++ProductID <<" ... "

std::cerr <<"Succeed" <<std::endl

}

//把新生产的产品放入缓冲区

void Append()

{

std::cerr <<"Appending a product ... "

g_buffer[in] = ProductID

in = (in+1)%SIZE_OF_BUFFER

std::cerr <<"Succeed" <<std::endl

//输出缓冲区当前的状态

for (int i=0i<SIZE_OF_BUFFER++i){

std::cout <<i <<": " <<g_buffer[i]

if (i==in) std::cout <<" <-- 生产"

if (i==out) std::cout <<" <-- 消费"

std::cout <<std::endl

}

}

//从缓冲区中取出一个产品

void Take()

{

std::cerr <<"Taking a product ... "

ConsumeID = g_buffer[out]

out = (out+1)%SIZE_OF_BUFFER

std::cerr <<"Succeed" <<std::endl

//输出缓冲区当前的状态

for (int i=0i<SIZE_OF_BUFFER++i){

std::cout <<i <<": " <<g_buffer[i]

if (i==in) std::cout <<" <-- 生产"

if (i==out) std::cout <<" <-- 消费"

std::cout <<std::endl

}

}

//消耗一个产品

void Consume()

{

std::cerr <<"Consuming " <<ConsumeID <<" ... "

std::cerr <<"Succeed" <<std::endl

}

//生产者

DWORD WINAPI Producer(LPVOID lpPara)

{

while(g_continue){

WaitForSingleObject(g_hFullSemaphore,INFINITE)

WaitForSingleObject(g_hMutex,INFINITE)

Produce()

Append()

Sleep(1500)

ReleaseMutex(g_hMutex)

ReleaseSemaphore(g_hEmptySemaphore,1,NULL)

}

return 0

}

//消费者

DWORD WINAPI Consumer(LPVOID lpPara)

{

while(g_continue){

WaitForSingleObject(g_hEmptySemaphore,INFINITE)

WaitForSingleObject(g_hMutex,INFINITE)

Take()

Consume()

Sleep(1500)

ReleaseMutex(g_hMutex)

ReleaseSemaphore(g_hFullSemaphore,1,NULL)

}

return 0

}

你上面列举的是读者写者问题,是互斥量,意思是只有获得互斥信号才能继续执行。

1、rmutex与wmutex的初始值均为1,wait一次就减一,signal一次就加一,其值只能是1或者是0

2、就拿读者来说吧(rmutex就是reader mutex),读者要去读的话必须得获得rmutex,那么就得wait(rmutex),

3、等有rmutex时,才准许你进门,等你进门了,你就不需要rmutex了(说白了,rmutex就是进出门的门卡,只有一张,进出都必须是一次一个人),所以你就释放它吧,那么就signal(rmutex),就是提醒后面的读者看哥不用这玩意儿了,你们爱咋咋用去,就扔给他们了,后面的读者看到有rmutex了也会做相同的步骤。出去的时候同样要等待门卡,没门卡出不去啊,也是wait和signal *** 作。

4、上面没有说明wmutex,其实在读者进去的时候要拿这个进去,wmutex可以理解为写好了的书,进去后你要拿着新写好的书看,如果没有新写好的,等吧,就是wait(wmutex),等获得新书的时候就进去看,等你看完的时候就把书扔在门口就是signal(wmutex)并说老子看完了,赶紧给老子写去,等待的写者看到有wmutex可以用的时候就屁颠屁颠儿的拿去写去了,那就是另一个写过程了。

读写锁与互斥量类似,不过读写锁的并行性更高。

读写锁可以有三种状态:(1)读模式加锁;(2)写模式加锁;(3)不加锁。

在写加锁状态时,在解锁之前,所有试图对这个锁加锁的线程都会被阻塞。在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问权限。但是如果线程希望以写模式加锁,它必须阻塞,直至所有的线程释放读锁。

读写锁很适合于对数据结构读的次数远大于写的情况。

相关函数:

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr)

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) // 成功则返回0,失败则返回错误代码

int pthread_rwlock_rdlock(pthread_rwlock_t *restrict rwlock) //读模式加锁

int pthread_rwlock_wrlock(pthread_rwlock_t *restrict rwlock)//写模式加锁

int pthread_rwlock_unlock(pthread_rwlock_t *restrick rwlock)

int pthread_rwlock_tryrdlock(pthread_rwlock_t *restrict rwlock)

int pthread_rwlock_trywrlock(pthread_rwlock_t *restrict rwlock)

int pthread_rwlock_trywrlock(pthread_rwlock_t *restrict rwlock)

相关示例:读者写者问题,这也是一个很经典的多线程题目,题目大意:有一个写者多个读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读取文件,同样有读者读文件时

#include <stdio.h>

#include <pthread.h>

#define Read_Num 2

pthread_rwlock_t lock

class Data

{

public:

Data(int i, float f): I(i),F(f)

{}

private:

int I

float F

}

Data *pdata = NULL

void *read(void * arg)

{

int id = (int)arg

while(true)

{

pthread_rwlock_rdlock(&lock)

printf(" reader %d is reading data!\n", id)

if(data == NULL)

{

printf("data is NULL\n")

}

else

{

printf("data: I = %d, F = %f \n", pdata->I, pdata->F)

}

pthread_rwlock_unlock(&lock)

}

pthread_exit(0)

}

void *write()

{

while(true)

{

pthread_rwlock_wrlock(&lock)

printf(" writer is writind data!\n")

if(pdata == NULL)

{

pdata = new Data(1, 1.1)

printf("Writer is writing data: %d, %f\n", pdata->I, pdata->F)

}

else

{

delete pdata

pdata = NULL

printf("writer free the data!")

}

pthread_rwlock_unlock(&lock)

}

pthread_exit(0)

}

void main()

{

pthread_t reader[Read_Num]

pthread_t writer

for(int i = 0i<Read_Numi++)

{

pthread_create(&read[i],NULL,read,(void *)i)

}

pthread_create(writer, NULL, write, NULL)

sleep(1)

return 0

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/8557010.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-18
下一篇 2023-04-18

发表评论

登录后才能评论

评论列表(0条)

保存