使用记录型信号量实现读写问题、生产者消费者问题

一、实验目的

1.生产者消费者问题

①实现生产者—消费者问题的模拟,以便更好的理解此经典进程同步问题。生产者-消费者问题是典型的PV操作问题,假设系统中有一个比较大的缓冲池,生产者的任务是只要缓冲池未满就可以将生产出的产品放入其中,而消费者的任务是只要缓冲池未空就可以从缓冲池中拿走产品。缓冲池被占用时,任何进程都不能访问。

②每一个生产者都要把自己生产的产品放入缓冲池,每个消费者从缓冲池中取走产品消费。在这种情况下,生产者消费者进程同步,因为只有通过互通消息才知道是否能存入产品或者取走产品。他们之间也存在互斥,即生产者消费者必须互斥访问缓冲池,即不能有两个以上的进程同时进行。

2.读者-写者问题

创建一个控制台进程,此进程包含n个线程。用这n个线程来表示n个读者或写者。每个线程按照设定进行读写操作。用信号量机制分别实现读者优先和写者优先的读者写者问题。 读者和写者问题的读写操作限制(包括读者优先和写者优先): 写写互斥:即不能有两个写者同时进行写操作。 读写互斥:即不能同时有一个线程在读,而另一个线程在写。 读读允许:即可以有一个或多个读者在读。 读者优先的附加限制:如果一个读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。 写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态才能开始读操作。

二、实验过程

生产者-消费者问题

问题描述

用信号量模拟生产者-消费者问题的过程。生产者和消费者两个线程共享同一个缓冲区,生产者不断向缓冲区中添加产品,消费者从缓冲区中消费产品。要保证缓冲区满了之后生产者不能再继续添加产品,需要等消费者至少消费一个产品之后生产者才能继续生产产品;缓冲区空了之后消费者不能再消费产品,需要等生产者至少生产一个产品之后消费者才能继续消费产品。

向缓冲区中添加产品和从缓冲区消费产品需要互斥操作保持同步。

生产者需要等待缓冲区有空间才能生产产品;消费者也不能在缓冲区为空时消费产品。这两个过程需要信号量来通知进行。

完整代码

#include <stdio.h> #include <pthread.h> #include <windows.h> #define N 100 #define true 1 #define producerNum 10 #define consumerNum 5 #define sleepTime 1000

typedef int semaphore; typedef int item; item buffer[N] = {0}; int in = 0; int out = 0; int proCount = 0; semaphore mutex = 1, empty = N, full = 0, proCmutex = 1;

void * producer(void * a){ while(true){ while(proCmutex <= 0); proCmutex--; proCount++; printf("生产一个产品ID%d, 缓冲区位置为%d\n",proCount,in); proCmutex++;

    while(empty <= 0){
        printf("缓冲区已满!\n");
    }
    empty--;
​
    while(mutex <= 0);
    mutex--;
​
    buffer[in] = proCount;
    in = (in + 1) % N;
​
    mutex++;
    full++;
    Sleep(sleepTime);
}

}

void * consumer(void *b){ while(true){ while(full <= 0){ printf("缓冲区为空!\n"); } full--;

    while(mutex <= 0);
    mutex--;
​
    int nextc = buffer[out];
    buffer[out] = 0;//消费完将缓冲区设置为0
​
    out = (out + 1) % N;
​
    mutex++;
    empty++;
​
    printf("\t\t\t\t消费一个产品ID%d,缓冲区位置为%d\n", nextc,out);
    Sleep(sleepTime);
}

}

int main() { pthread_t threadPool[producerNum+consumerNum]; int i; for(i = 0; i < producerNum; i++){ pthread_t temp; if(pthread_create(&temp, NULL, producer, NULL) == -1){ printf("ERROR, fail to create producer%d\n", i); exit(1); } threadPool[i] = temp; }//创建生产者进程放入线程池

for(i = 0; i < consumerNum; i++){
    pthread_t temp;
    if(pthread_create(&temp, NULL, consumer, NULL) == -1){
        printf("ERROR, fail to create consumer%d\n", i);
        exit(1);
    }
    threadPool[i+producerNum] = temp;
}//创建消费者进程放入线程池
void * result;
for(i = 0; i < producerNum+consumerNum; i++){
    if(pthread_join(threadPool[i], &result) == -1){
        printf("fail to recollect\n");
        exit(1);
    }
}//运行线程池
return 0;
}

读者-写者问题

代码:

#include<iostream> #include<string> #include <conio.h> #include <stdlib.h> #include <stdio.h> #include <fstream> #include <io.h> #include <string.h> #include<algorithm> #include<Windows.h> //多线程编程 #include<process.h> using namespace std;

#define READER 'R' //读者 #define WRITER 'W' //写者 #define INTE_PER_SEC 1000 //每秒时钟中断的数目 #define MAX_THREAD_NUM 64 //最大线程数目

//变量声明初始化 int readercount = 0;//记录等待的读者数目 int writercount = 0;//记录等待的写者数目

HANDLE rc_mutex;//因为读者数量而添加的互斥信号量,用于读者优先

HANDLE rc2_mutex;//因为读者数量而添加的互斥信号量,用于写者优先 HANDLE wc_mutex;//因为写者数量而添加的互斥信号量 HANDLE book;//互斥访问信号量 HANDLE wrt;//保证每次只有一个写者进行写操作,当写者的数量writercount等于0的时候,则证明此时没有没有读者了,释放信号量book HANDLE mutex;//避免写者同时与多个读者进行竞争,读者中信号量RWMutex比mutex3先释放,则一旦有写者,写者可马上获得资源

struct thread_info { int id; //线程序号 char entity; //线程类别(判断是读者线程还是写者线程) double delay; //线程延迟时间 double lastTime; //线程读写操作时间 }; /*****/ //读者优先 //进程管理-读者线程 void rp_threadReader(void p) { DWORD m_delay; //延迟时间 DWORD m_persist; //读文件持续时间 int m_serial; //线程序号 //从参数中获得信息 m_serial = ((thread_info)(p))->id; m_delay = (DWORD)(((thread_info*)(p))->delay INTE_PER_SEC); m_persist = (DWORD)(((thread_info)(p))->lastTime *INTE_PER_SEC); Sleep(m_delay); //延迟等待

printf("读者进程%d申请读文件.\n", m_serial);
//cout << "读者进程"<< m_serial<<"申请读文件." << endl;
​
WaitForSingleObject(rc_mutex, -1);//对readercount互斥访问
if (readercount == 0)WaitForSingleObject(book, -1);//第一位读者申请书
readercount++;
ReleaseSemaphore(rc_mutex, 1, NULL);//释放互斥信号量rc_mutex
​
printf("读者进程%d开始读文件.\n", m_serial);
Sleep(m_persist);
printf("读者进程%d完成读文件.\n", m_serial);
​
WaitForSingleObject(rc_mutex, -1);//修改readercount
readercount--;//读者读完
if (readercount == 0)ReleaseSemaphore(book, 1, NULL);//释放书籍,写者可写
ReleaseSemaphore(rc_mutex, 1, NULL);//释放互斥信号量rc_mutex

} /*****/ //读者优先 //进程管理-写者线程 void rp_threadWriter(void p) { DWORD m_delay; //延迟时间 DWORD m_persist; //读文件持续时间 int m_serial; //线程序号 //从参数中获得信息 m_serial = ((thread_info)(p))->id; m_delay = (DWORD)(((thread_info*)(p))->delay INTE_PER_SEC); m_persist = (DWORD)(((thread_info)(p))->lastTime INTE_PER_SEC); Sleep(m_delay); //延迟等待 printf("写者进程%d申请写文件.\n", m_serial); WaitForSingleObject(book, INFINITE);//申请资源 /write is performed*/ printf("写者进程%d开始读文件.\n", m_serial); Sleep(m_persist); printf("写者进程%d完成读文件.\n", m_serial); ReleaseSemaphore(book, 1, NULL);//释放资源 } //读者优先 void ReaderPriority(char *file) { DWORD n_thread = 0; //线程数目 DWORD thread_ID; //线程ID DWORD wait_for_all; //等待所有线程结束

                            //创建信号量
rc_mutex = CreateSemaphore(NULL, 1, 1, "mutex_for_readcount");//读者对count修改互斥信号量,初值为1,最大为1
book = CreateSemaphore(NULL, 1, 1, NULL);//书籍互斥访问信号量,初值为1,最大值为1
​
HANDLE h_Thread[MAX_THREAD_NUM];//线程句柄,线程对象的数组
thread_info thread_info[MAX_THREAD_NUM];
​
int id = 0;
readercount = 0;               //初始化readcount
ifstream inFile;
inFile.open(file);
cout << "读者优先:" << endl;
while (inFile)
{
    //读入每一个读者,写者的信息
    inFile >> thread_info[n_thread].id;
    inFile >> thread_info[n_thread].entity;
    inFile >> thread_info[n_thread].delay;
    inFile >> thread_info[n_thread++].lastTime;
    inFile.get();
}
for (int i = 0; i<(int)(n_thread); i++)
{
    if (thread_info[i].entity == READER || thread_info[i].entity == 'r')
    {
        //创建读者进程
        h_Thread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(rp_threadReader), &thread_info[i], 0, &thread_ID);
    }
    else
    {
        //创建写线程
        h_Thread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(rp_threadWriter), &thread_info[i], 0, &thread_ID);
    }
}
//等待子线程结束
​
//关闭句柄
wait_for_all = WaitForMultipleObjects(n_thread, h_Thread, TRUE, -1);
cout << endl;
cout << "所有读者写者已经完成操作!!" << endl;
for(int i = 0; i<(int)(n_thread); i++)
    CloseHandle(h_Thread[i]);
CloseHandle(rc_mutex);
CloseHandle(book);

} /*****/ //写者优先 //进程管理-读者线程 void wp_threadReader(void p) { DWORD m_delay; //延迟时间 DWORD m_persist; //读文件持续时间 int m_serial; //线程序号 //从参数中获得信息 m_serial = ((thread_info)(p))->id; m_delay = (DWORD)(((thread_info*)(p))->delay INTE_PER_SEC); m_persist = (DWORD)(((thread_info)(p))->lastTime *INTE_PER_SEC); Sleep(m_delay); //延迟等待

printf("读者进程%d申请读文件.\n", m_serial);
WaitForSingleObject(mutex, -1);
WaitForSingleObject(book, -1);
WaitForSingleObject(rc2_mutex, -1);//对readercount互斥访问
if (readercount == 0)WaitForSingleObject(wrt, -1);//第一位读者申请书,同时防止写者进行写操作
readercount++;
​
ReleaseSemaphore(rc2_mutex, 1, NULL);//释放互斥信号量rc_mutex
ReleaseSemaphore(book, 1, NULL);//释放互斥信号量book
ReleaseSemaphore(mutex, 1, NULL);//释放互斥信号量mutex
                                 /* reading is performed */
printf("读者进程%d开始读文件.\n", m_serial);
Sleep(m_persist);
printf("读者进程%d完成读文件.\n", m_serial);
WaitForSingleObject(rc2_mutex, -1);//修改readercount
readercount--;//读者读完
if (readercount == 0)ReleaseSemaphore(wrt, 1, NULL);//释放资源,写者可写
ReleaseSemaphore(rc2_mutex, 1, NULL);//释放互斥信号量rc_mutex

} /*****/ //写者优先 //进程管理-写者线程 void wp_threadWriter(void p) { DWORD m_delay; //延迟时间 DWORD m_persist; //读文件持续时间 int m_serial; //线程序号 //从参数中获得信息 m_serial = ((thread_info)(p))->id; m_delay = (DWORD)(((thread_info*)(p))->delay INTE_PER_SEC); m_persist = (DWORD)(((thread_info)(p))->lastTime *INTE_PER_SEC); Sleep(m_delay); //延迟等待

printf("写者进程%d申请写文件.\n", m_serial);
WaitForSingleObject(wc_mutex, -1);//对writercount互斥访问
if (writercount == 0)WaitForSingleObject(book, -1);//第一位写者申请资源
writercount++;
ReleaseSemaphore(wc_mutex, 1, NULL);//释放资源
​
WaitForSingleObject(wrt, -1);
/*write is performed*/
printf("写者进程%d开始写文件.\n", m_serial);
Sleep(m_persist);
printf("写者进程%d完成写文件.\n", m_serial);
ReleaseSemaphore(wrt, 1, NULL);//释放资源
​
WaitForSingleObject(wc_mutex, -1);//对writercount互斥访问
writercount--;
if (writercount == 0)ReleaseSemaphore(book, 1, NULL);//释放资源
ReleaseSemaphore(wc_mutex, 1, NULL);//释放资源

} //写者优先 void WriterPriority(char *file) { DWORD n_thread = 0; //线程数目 DWORD thread_ID; //线程ID DWORD wait_for_all; //等待所有线程结束

                            //创建信号量
rc2_mutex = CreateSemaphore(NULL, 1, 1, "mutex_for_readercount");//读者对count修改互斥信号量,初值为1,最大为1
wc_mutex = CreateSemaphore(NULL, 1, 1, "mutex_for_writercount");//写者对count修改互斥信号量,初值为1,最大为1
wrt = CreateSemaphore(NULL, 1, 1, NULL);//
mutex = CreateSemaphore(NULL, 1, 1, NULL);//
book = CreateSemaphore(NULL, 1, 1, NULL);//书籍互斥访问信号量,初值为1,最大值为1
​
HANDLE h_Thread[MAX_THREAD_NUM];//线程句柄,线程对象的数组
thread_info thread_info[MAX_THREAD_NUM];
​
int id = 0;
readercount = 0;               //初始化readcount
writercount = 0;
ifstream inFile;
inFile.open(file);
cout << "写者优先:" << endl;
while (inFile)
{
    //读入每一个读者,写者的信息
    inFile >> thread_info[n_thread].id;
    inFile >> thread_info[n_thread].entity;
    inFile >> thread_info[n_thread].delay;
    inFile >> thread_info[n_thread++].lastTime;
    inFile.get();
}
for (int i = 0; i<(int)(n_thread); i++)
{
    if (thread_info[i].entity == READER || thread_info[i].entity == 'r')
    {
        //创建读者进程
        h_Thread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(wp_threadReader), &thread_info[i], 0, &thread_ID);
    }
    else
    {
        //创建写线程
        h_Thread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(wp_threadWriter), &thread_info[i], 0, &thread_ID);
    }
}
//等待子线程结束
​
//关闭句柄
wait_for_all = WaitForMultipleObjects(n_thread, h_Thread, TRUE, -1);
cout << endl;
cout << "所有读者写者已经完成操作!!" << endl;
for (int i = 0; i<(int)(n_thread); i++)
    CloseHandle(h_Thread[i]);
CloseHandle(wc_mutex);
CloseHandle(rc2_mutex);
CloseHandle(book);

} //主函数 int main() { char choice; cout << " 欢迎进入读者写者模拟程序 " << endl; while (true) { //打印提示信息 cout << " 请输入你的选择 " << endl; cout << " 1、读者优先" << endl; cout << " 2、写者优先" << endl; cout << " 3、退出程序" << endl; cout << endl; //如果输入信息不正确,继续输入 do { choice = (char)_getch(); } while (choice != '1'&&choice != '2'&&choice != '3');

    system("cls");
    //选择1,读者优先
    if (choice == '1')
        //ReaderPriority("thread.txt");
        ReaderPriority(const_cast<char *>("thread.txt"));
    //选择2,写者优先
    else if (choice == '2')
        WriterPriority(const_cast<char *>("thread.txt"));
    //选择3,退出
    else
        return 0;
    //结束
    printf("\nPress Any Key to Coutinue");
    _getch();
    system("cls");
}
return 0;
}

三、实验结果

生产者-消费者问题

读者-写者问题

测试文本

四、实验心得

在实验中,我使用了记录型信号量来实现读写问题和生产者消费者问题。通过这次实验,我深刻体会到记录型信号量在多线程编程中的重要性和灵活性。

在读写问题中,我使用了两个记录型信号量来实现对共享资源的读写操作。当有读操作时,我使用一个记录型信号量来控制读者数量,保证在有写操作时读者无法同时访问共享资源;当有写操作时,我使用另一个记录型信号量来保证只有一个写者能够访问共享资源,避免读写冲突。通过这种方式,我成功地解决了读写问题,确保了读写操作的正确性和一致性。

在生产者消费者问题中,我同样使用了记录型信号量来实现生产者和消费者之间的同步。我使用了两个记录型信号量来控制生产者和消费者的进程数量,确保生产者和消费者能够交替执行,避免了生产者和消费者之间的竞争和死锁。通过这种方式,我成功地解决了生产者消费者问题,确保了生产者和消费者之间的协作和同步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值