一、基本信息
xxx 711103xx 2012年4月29日
二、实验目的
通过实验,掌握Windows和Linux环境下互斥锁和信号量的实现方法,加深对临界区问题和进程同步机制的理解,同时巩固利用Windows API和Pthread API进行多线程编程的方法。
三、实验内容
1. 在Windows操作系统上,利用Win32 API提供的信号量机制,编写应用程序实现生产者——消费者问题。
2. 在Linux操作系统上,利用Pthread API提供的信号量机制,编写应用程序实现生产者——消费者问题。
3. 两种环境下,生产者和消费者均作为线程,并通过empty、full、mutex三个信号量实现对缓冲进行插入与删除。
4. 通过打印缓冲区中的内容至屏幕,来验证应用程序的正确性。
四、实验步骤
1. 创建3个信号量:Mutex、Full、Empty
2. 主程序创建10个生产者线程和10个消费者线程,之后休眠一段时间
3. 生产者线程中,休息一段2s后,生产一个0~10的随机数放入缓冲区里。利用信号量Mutex产生对缓冲区使用的互斥功能,利用Empty和Full信号量来对缓冲区进行增加项
4. 消费者线程中,休息4s时间后,消费一个缓冲区的数据。利用信号量Mutex产生对缓冲区使用的互斥功能,利用Empty和Full信号量来对缓冲区进行增加项
5. 主程序执行一段时间后,结束整个程序
五、主要数据结构及其说明
产品数量最大值
const int MAX_SIZE = 10;
缓冲区:
int buffer[BUFFER_SIZE];
int front; int rear; bool full;
三个互斥信号量:
HANDLE Mutex; HANDLE Full; HANDLE Empty;
有关操作:
用WaitForSingleSignal函数可以获得一个Mutex的所有权,类似于P操作,而ReleaseMutex函数可以释放一个Mutex的所有权,类似于V操作。
用EnterCriticalSection函数可以进入一个CriticalSection,类似于P操作,而LeaveCricalSection函数离开一个CricalSection,类似于V操作。
(linux )
六、程序运行时的初值和运行结果
Windows:
结果:
Linux:
Linux下与windows结果一致。两个不同环境下的程序运行效果是相同的。
七、实验体会
本次实验是关于生产者与消费者之间互斥和同步的问题。问题的实质是P、V操作,实验设一个共享缓冲区,生产者和消费者互斥的使用,当一个线程使用缓冲区的时候,另一个让其等待直到前一个线程释放缓冲区为止。
通过实验,我深入地了解PV操作的实质和其重要性。进一步学习了 Windows 和Linux 环境下互斥锁和信号量的实现方法,加深了对临界区问题和进程同步机制的理解,同时巩固利用Windows API 和PthreadAPI 进行多线程编程的方法。另外,linux和windows的API之间几乎是一一对应的关系,差别不大。
八、源程序并附上注释
Windows:
Linux:
Linux:
main.cpp
#include "buffer.h"
#include #include #include #include #include using namespace std; /* the buffer */ buffer_item buffer[BUFFER_SIZE]; int front; int rear; bool full; /* the semaphores*/ pthread_mutex_t Mutex; sem_t Full; sem_t Empty; /* the output file */ ofstream fout; void showBuffer(){ cout << "\\nBuffer: "; fout << "\\nBuffer: "; if(front!=rear||full){ int i = front; do{ cout << buffer[i] << ' '; fout << buffer[i] << ' '; i=(i+1)%BUFFER_SIZE; }while(i!=rear); } else { cout << " - "; fout << " - "; } cout << "\\n\\n"; fout << "\\n\\n"; } int insert_item(buffer_item item){ /* insert item into buffer return 0 if successful, otherswise return -1 indicating an error condition */ int condition = -1; sem_wait(&Empty); pthread_mutex_lock(&Mutex); if(!full){ buffer[rear] = item; rear = (rear+1)%BUFFER_SIZE; if(rear == front) full = true; condition = 0; cout << "producer produced " << item << endl; fout << "producer produced " << item << endl; showBuffer(); } pthread_mutex_unlock(&Mutex); sem_post(&Full); return condition; } int remove_item(buffer_item *item){ /* remove an object from buffer placing it in item return 0 if successful, otherwise return -1 indicating an error condition */ int condition = -1; sem_wait(&Full); pthread_mutex_lock(&Mutex); if(front!=rear||full){ *item = buffer[front]; front = (front+1)%BUFFER_SIZE; full = false; condition = 0; cout << "consumer consumed " << *item << endl; fout << "consumer consumed " << *item << endl; showBuffer(); } pthread_mutex_unlock(&Mutex); sem_post(&Empty); return condition; } void* producer(void *param); void* consumer(void *param); int main(int argc, char*argv[]) { /* Initialize buffer */ front = 0; rear = 0; full = false; /* Initialize semaphores */ pthread_mutex_init(&Mutex,NULL); sem_init(&Full,0,BUFFER_SIZE); sem_init(&Empty,0,BUFFER_SIZE); /* Initialize output file */ fout.open("pcBuffer.txt"); /* Create producer thread */ pthread_attr_t attr; pthread_attr_init(&attr); pthread_t producerThread,consumerThread; pthread_create(&producerThread,&attr,producer,NULL); /* Create consumer thread */ pthread_create(&consumerThread,&attr,consumer,NULL); /* Sleep */ pthread_join(producerThread,NULL); //pthread_join(consumerThread,NULL); /* Exit */ return 0; } threads.cpp #include "buffer.h" #include #include #include #include using std::cout; using std::endl; int insert_item(buffer_item item); int remove_item(buffer_item *item); void showBuffer(); void* producer(void *param){ srand((unsigned)time(NULL)); buffer_item item; while(true){ /* sleep for a random period of time */ sleep(((float)(rand()%4000))/1000); /* generate a random number */ item = rand()%100; if(insert_item(item)) cout << "report error condition in producer" << endl; } return NULL; } void* consumer(void *param){ srand((unsigned)time(NULL)); buffer_item item; while(true){ /* sleep for a random period of time */ sleep(((float)(rand()%8000))/1000); if(remove_item(&item)) { cout << "report error condition in consumer" << endl; } } return NULL; } buffer.h #ifndef BUFFER_H_INCLUDED #define BUFFER_H_INCLUDED /* buffer.h */ typedef int buffer_item; #define BUFFER_SIZE 5 #endif // BUFFER_H_INCLUDED