Linux实验报告 消费者与生产者 多线程
- 格式:doc
- 大小:420.50 KB
- 文档页数:7
实验目标在本次实验中,使用信号量,编写一段程序解决生产者/消费者同步问题。
完成本次试验,理解Nachos的信号量是如何实现的生产者/消费者问题是如何用信号量实现的在Nachos中是如何创建并发线程的在Nachos下是如何测试和debug的实验环境Linux关键源代码注释Ringring与slot的关系如图所示,在prodcons++中,定义ring的BUFF_SIZE大小为3.生产者nempty->P();查看buffer是否有空,if nempty>0,nempty=nempty -1(用nempty代替nempty.value,下nfull同).mutex->P();加锁.向ring中放入message信息.mutex->V();解锁.nfull->V();通知消费者buffer有新信息,nfull=nfull+1.关键代码如下:voidProducer(_int which){int num;slot *message = new slot(0,0);//建立slot实例,此信息message将被放到ring buffer里。
每个信息message有一个id和一个value。
//每个生产者产生的商品的个数必须使用N_MESSG限定,否则程序没有结束for (num = 0; num < N_MESSG ; num++) {message->thread_id=which; //producer的idmessage->value=num; //产生的message的编号nempty->P();mutex->P();ring->Put(message);mutex->V();nfull->V();}}消费者nfull->P();查看buffer中是否有信息,if nfull>0,nfull-1.mutex->P();加锁.从ring buffer中取出信息.mutex->V();解锁.nempty->V();通知生产者bufferr有空nempty=nempty+1.关键代码如下:voidConsumer(_int which){char str[MAXLEN];char fname[LINELEN];int fd;slot *message = new slot(0,0);// to form a output file name for this consumer thread.// all the messages received by this consumer will be recorded in // this file.sprintf(fname, "tmp_%d", which);// create a file. Note that this is a UNIX system call.if ( (fd = creat(fname, 0600) ) == -1){perror("creat: file create failed");Exit(1);}//不需要规定每个消费者消费的商品的个数for (; ; ) {nfull->P();mutex->P();ring->Get(message);mutex->V();nempty->V();// form a string to record the messagesprintf(str,"producer id --> %d; Message number --> %d;\n",message->thread_id,message->value);// write this string into the output file of this consumer.// note that this is another UNIX system call.if ( write(fd, str, strlen(str)) == -1 ) {perror("write: write failed");Exit(1);}}}生产者/消费者问题的解决mutex = new Semaphore("mutux",1);信号量初始化为1,才能起到加锁功能nfull = new Semaphore("full",0);nfull的大小在生产者没生产前为0nempty = new Semaphore("empty",BUFF_SIZE);nempty的大小应该为buffer的大小创建线程生成一个生产者的代码:producers[i] = new Thread(prod_names[i]);producers[i] -> Fork(Producer,i);关键代码如下:voidProdCons(){int i;//建立信号量mutex = new Semaphore("mutux",1);nfull = new Semaphore("full",0);nempty = new Semaphore("empty",BUFF_SIZE);// 建立ring buffer,大小为BUFF_SIZEring = new Ring(BUFF_SIZE);// 建立并唤醒N_PROD个生产者线程for (i=0; i < N_PROD; i++){sprintf(prod_names[i], "producer_%d", i);//使用prod_names[i]创建线程producers[i] = new Thread(prod_names[i]);//行为为Producer定义,i为Producer参数producers[i] -> Fork(Producer,i);};// 建立并唤醒N_CONS 个消费者线程for (i=0; i < N_CONS; i++){sprintf(cons_names[i], "consumer_%d", i);//使用cons_names[i]创建线程consumers[i] = new Thread(cons_names[i]);//定义行为为Consumer,i为Consumer参数consumers[i] -> Fork(Consumer,i);};}调试记录源代码中exit(0)没有大写,增加了许多无谓的劳动。
实验报告
./clone输出结果:
实验讨论:
由程序1结果可知,使用fork()语句创建的子进程与其父进程具有相对独立的地址空间,在此解决生产者-消费者问题里,可以采用pipe()进行通讯。
子进程复制了父进程的打开文件表,所以pipe()所建立的通信管道可被子进程继承,生产和消费进程可以通过对同一通信管道文件的读书进行通讯。
由程序2结果可知:clone()语句在创建进程时,可通过参数设定子进程与父进程是否共享存储空间,从而可以创建真正意义上的程序。
生产者和消费者进程共享内在,从而可以通过共享交换数据。
但多个进程共享共存需要互斥机制。
三.实验流程图
程序二流程图:
基于clone()系统调用
父进程:
生产者子进程(Producer):。
案例10:生产者-消费者模型是线程同步中的一个经典案例。
假设有两个线程,这两个线程同时操作一个共享资源(一般称为汇聚),其中一个模拟生产者行为,生产共享资源,当容器存满时,生产者无法向其中放入产品;另一个线程模拟消费者行为,消费共享资源,当产品数量为0时,消费者无法获取产品,应阻塞等待。
显然,为防止数据混乱,每次只能由生产者、消费者中的一个,操作共享资源。
本案例要求使用程序实现简单的生产者-消费者模型(可假设容器无限大)。
案例实现如下:1#include <stdio.h>2#include <stdlib.h>3#include <unistd.h>4#include <pthread.h>5struct msg {6 struct msg *next;7 int num;8};9struct msg *head;10pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; //初始化条件变量11pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; //初始化互斥锁12//消费者13void *consumer(void *p)14{15 struct msg *mp;16 for (;;) {17 pthread_mutex_lock(&lock); //加锁18 //若头结点为空,表明产品数量为0,消费者无法消费产品19 while (head == NULL) {20 pthread_cond_wait(&has_product, &lock); //阻塞等待并解锁21 }22 mp = head;23 head = mp->next; //模拟消费一个产品24 pthread_mutex_unlock(&lock);25 printf("-Consume ---%d\n", mp->num);26 free(mp);27 sleep(rand() % 5);28 }29}30//生产者31void *producer(void *p)32{33 struct msg *mp;34 while (1) {35 mp = malloc(sizeof(struct msg));36 mp->num = rand() % 1000 + 1; //模拟生产一个产品37 printf("-Produce ---%d\n", mp->num);38 pthread_mutex_lock(&lock); //加锁39 mp->next = head; //插入结点(添加产品)40 head = mp;41 pthread_mutex_unlock(&lock); //解锁42 pthread_cond_signal(&has_product); //唤醒等待在该条件变量上的一个线程43 sleep(rand() % 5);44 }45}46int main(int argc, char *argv[])47{48 pthread_t pid, cid;49 srand(time(NULL));50 //创建生产者、消费者线程51 pthread_create(&pid, NULL, producer, NULL);52 pthread_create(&cid, NULL, consumer, NULL);53 //回收线程54 pthread_join(pid, NULL);55 pthread_join(cid, NULL);56 return 0;57}。
Linux⽣产者消费者简单例⼦学习#if 0Linux实现⽣产者消费者模型1. 防⽌虚假唤醒2. 唤醒线程的时机很重要,否则会导致线程多次访问锁,影响性能#endif#include <unistd.h>#include <stdio.h>#include <iostream>#include <pthread.h>using namespace std;int g_value = 0;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t cond = PTHREAD_COND_INITIALIZER;void* consumer1(void* arg){printf("consumer[%d] begin consume.\n", (int)(*((int*)(arg))));pthread_mutex_lock(&mutex);printf("consumer[%d] pthread_mutex_lock.\n", (int)(*((int*)(arg))));while (g_value <= 0) {//防⽌虚假唤醒printf("consumer[%d] begin wait.\n", (int)(*((int*)(arg))));int ret = pthread_cond_wait(&cond, &mutex);if (ret) {printf("pthread_cond_wait error ret[%d].\n", ret);return NULL;}printf("consumer[%d] end wait.\n", (int)(*((int*)(arg))));}--g_value;printf("consumer[%d] g_value:[%d].\n", (int)(*((int*)(arg))), g_value);pthread_mutex_unlock(&mutex);printf("consumer[%d] pthread_mutex_unlock.\n", (int)(*((int*)(arg))));return NULL;}void* consumer2(void* arg){printf("consumer[%d] begin consume.\n", (int)(*((int*)(arg))));pthread_mutex_lock(&mutex);printf("consumer[%d] pthread_mutex_lock.\n", (int)(*((int*)(arg))));while (g_value <= 0) {//防⽌虚假唤醒printf("consumer[%d] begin wait.\n", (int)(*((int*)(arg))));int ret = pthread_cond_wait(&cond, &mutex);if (ret) {printf("pthread_cond_wait error ret[%d].\n", ret);return NULL;}printf("consumer[%d] end wait.\n", (int)(*((int*)(arg))));}--g_value;printf("consumer[%d] g_value:[%d].\n", (int)(*((int*)(arg))), g_value);pthread_mutex_unlock(&mutex);printf("consumer[%d] pthread_mutex_unlock.\n", (int)(*((int*)(arg))));return NULL;}void* producer(void* arg){cout << "producer begin product." << endl;pthread_mutex_lock(&mutex);printf("producer pthread_mutex_lock.\n");++g_value;cout << "producer g_value: " << g_value << endl;if (g_value > 0) {cout << "producer begin pthread_cond_broadcast." << endl;int ret = pthread_cond_broadcast(&cond);if (ret) {printf("pthread_cond_broadcast error ret[%d].\n", ret);return NULL;}cout << "producer end pthread_cond_broadcast." << endl;}printf("producer begin pthread_mutex_unlock.\n");int ret = pthread_mutex_unlock(&mutex);if (ret) {printf("pthread_mutex_unlock error ret[%d].\n", ret);return NULL;}printf("producer end pthread_mutex_unlock.\n");return NULL;}int join(pthread_t tid, void **retval){int ret = pthread_join(tid, retval);if (ret) {return ret;}else {return0;}}int main(){pthread_t tid_consumer[2] = {0};pthread_t tid_producer = 0;int ret = -1;int _consumer1 = 1;ret = pthread_create(&tid_consumer[0], NULL, &consumer1, (void*)(&_consumer1)); if (ret) {printf("pthread_create error ret[%d].\n", ret);return -1;}sleep(1);int _consumer2 = 2;ret = pthread_create(&tid_consumer[1], NULL, &consumer2, (void*)(&_consumer2)); if (ret) {printf("pthread_create error ret[%d].\n", ret);return -1;}sleep(5);ret = pthread_create(&tid_producer, NULL, &producer, NULL);if (ret){printf("pthread_create error ret[%d].\n", ret);return -1;}sleep(2);for (int i = 0; i < sizeof(tid_consumer)/sizeof(tid_consumer[0]); ++i){ret = join(tid_consumer[i], NULL);if (ret) {printf("join error ret[%d].\n", ret);}}ret = join(tid_producer, NULL);if (ret) {printf("join error ret[%d].\n", ret);return -1;}printf("pthread join success.\n");return0;}。
实验课程:操作系统实验实验编号:实验名称:生产者消费者算法实验人员:实验日期:上交日期:实验室:实验评价:一、目的和要求生产者消费者算法是操作系统中很重要的同步算法,通过本实验加深对互斥信号量和同步信号量的理解,掌握如何用信号量机制实现生产者消费者之间的同步算法。
二、实验内容运用高级语言模拟实现生产者消费者算法,要求实现对缓冲池的互斥访问和生产者进程与消费者进程之间的同步,观察程序的运行情况并分析执行结果。
三、实验环境1.PC微机。
2.Windows 操作系统。
3.C/C++/VB开发集成环境。
四、实验结果1.程序源代码:生产者&消费者如下图:# include <stdio.h># include <stdlib.h># include <time.h># include <sys/types.h># include <pthread.h># include <semaphore.h># include <string.h># include <unistd.h>#define BUFFER_SIZE 5typedef int buffer_item;//semaphoressem_t empty, full, mutex;//bufferbuffer_item buffer[BUFFER_SIZE]; int in, out;//存储数据的结构体struct data {int id;int opTime;int lastTime;int productId;};//有限缓存插入--生产int insert_item(buffer_item item) {/* insert item into buffer */buffer[out] = item;out = (out + 1) % BUFFER_SIZE;return 0;}//有限缓存删除--消费int remove_item(buffer_item *item) {/* remove an object from buffer and then place it in item */ *item = buffer[in];in = (in + 1) % BUFFER_SIZE;return 0;}//生产者void *producer(void* param) {int productId = ((struct data*)param)->productId;int lastTime = ((struct data*)param)->lastTime;int id = ((struct data*)param)->id;free(param);sleep(opTime);sem_wait(&empty);sem_wait(&mutex);/* critical section *///add a iteminsert_item(productId);sleep(lastTime);printf("Thread %d: Producer produce %d\n", id, productId);sem_post(&mutex);sem_post(&full);pthread_exit(0);}//消费者void *consumer(void* param) {int opTime = ((struct data*)param)->opTime;int id = ((struct data*)param)->id;free(param);sleep(opTime);sem_wait(&full);sem_wait(&mutex);/* critical section *///remove a itembuffer_item item;remove_item(&item);sleep(lastTime);printf("Thread %d: Consumer consume %d\n", id, item);sem_post(&mutex);sem_post(&empty);pthread_exit(0);}int main() {//pthreadpthread_t tid; // the thread identifierpthread_attr_t attr; //set of thread attributes/* get the default attributes */pthread_attr_init(&attr);//initial the semaphoressem_init(&mutex, 0, 1);sem_init(&empty, 0, BUFFER_SIZE);sem_init(&full, 0, 0);in = out = 0;int id = 0;while(scanf("%d", &id) != EOF) {char role; //producer or consumerint opTime; //operating timeint lastTime; //run timeint productId; //product idscanf("%c%d%d", &role, &opTime, &lastTime);struct data* d = (struct data*)malloc(sizeof(struct data));d->id = id;d->opTime = opTime;d->lastTime = lastTime;if(role == 'P') {scanf("%d", &productId);d->productId = productId;pthread_create(&tid, &attr, producer, d);}else if(role == 'C')pthread_create(&tid, &attr, consumer, d);}//释放信号量sem_destroy(&mutex);sem_destroy(&empty);sem_destroy(&full);return 0;}---------------------2.实验报告。
实验三:生产者与消费者一、实验目的1.学习和掌握操作系统中进程之间的通信;2.理解和掌握使用信号量机制来是想进程之间的同步和互斥;3.学习使用创建文件对象,并利用文件映射对象来实现数据通信。
二、实验内容•一个大小为6的缓冲区,初始为空,每个缓冲区能存放一个长度若为10个字符的字符串。
•2个生产者–随机等待一段时间,往缓冲区添加数据,–若缓冲区已满,等待消费者取走数据后再添加–重复12次•3个消费者–随机等待一段时间,从缓冲区读取数据–若缓冲区为空,等待生产者添加数据后再读取–重复8次说明:•显示每次添加和读取数据的时间及缓冲区的状态•生产者和消费者用进程模拟,缓冲区用共享内存来实现三、实验环境1.Windows下:Windows8 ,Visual studio 20132.Linux下:Linux Ubuntu 4,gcc四、程序设计与实现1.Windows下:A.主要函数说明:(1)PROCESS_INFORMATIONStartClone(intnCloneID)功能:用来创建5个相同的进程,前两个为生产者,后三两个为消费者,赋予其不同的ID值,返回进程的信息。
(2)CreateSemaphore();功能:创建3个信号量:full,empty,mutex。
来互斥的访问缓冲区,实现通信。
(3)CreateFileMapping()功能:在当前运行的进程中创建文件映射对象,来模拟共享缓冲区MapViewOfFile()功能:在此文件映射上创建视图映射到当前应用程序的地址空间B.程序流程图实验代码如下://#include"stdafx.h"#include<stdio.h>#include<windows.h>#include<time.h>static HANDLE hMutexMapping=INVALID_HANDLE_VALUE;int num=0;HANDLE lpHandle[10];struct buf{int num;int read;int write;int buffer[5];};BOOL StartClone(){int i;BOOL bCreateOK;PROCESS_INFORMATION pi;TCHAR szFilename[MAX_PATH];GetModuleFileName(NULL,szFilename,MAX_PATH);TCHAR szCmdLine[MAX_PATH];for ( i = 0; i < 3; i++){sprintf(szCmdLine,"\"%s\" consumer %d",szFilename,i);STARTUPINFO si;ZeroMemory(reinterpret_cast<void*>(&si),sizeof(si)); si.cb=sizeof(si);bCreateOK=CreateProcess(szFilename,szCmdLine,NULL,NULL,FALSE,CREATE_DEFAULT_ERROR_MODE,NULL,NULL,&si,&pi);if (!bCreateOK){return false;lpHandle[num]=pi.hProcess;num++;}for ( i = 0; i < 2; i++){sprintf(szCmdLine,"\"%s\" productor %d",szFilename,i);STARTUPINFO si;ZeroMemory(reinterpret_cast<void *>(&si),sizeof(si)); si.cb=sizeof(si);bCreateOK=CreateProcess(szFilename,szCmdLine,NULL,NULL,FALSE,CREATE_DEFAULT_ERROR_MODE,NULL,NULL,&si,&pi);if (!bCreateOK)return false;}lpHandle[num]=pi.hProcess;num++;}return true;}void Parent(){printf("Creating the child process and waited child process to quit.\n");hMutexMapping=CreateMutex(NULL,true,"mutex");HANDLE hMapping=CreateFileMapping(NULL,NULL,PAGE_READWRITE,0,sizeof(LONG),"map");if (hMapping!=INVALID_HANDLE_VALUE){LPVOID pData=MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,0);if (pData!=NULL){ZeroMemory(pData,sizeof(LONG));}struct buf *pnData=reinterpret_cast<struct buf*>(pData);pnData->read=0;pnData->write=0;pnData->num=0;memset(pnData->buffer,0,sizeof(pnData->buffer)); UnmapViewOfFile(pData);}CreateSemaphore(NULL,3,3,"EMPTY");CreateSemaphore(NULL,0,3,"FULL");BOOL bCreateOK=StartClone();if (!bCreateOK){//printf("Create child process failed.\n");}else{//printf("Create child process success.\n");}ReleaseMutex(hMutexMapping);}void Productor(int n){int j;printf("Productor is running.\n");hMutexMapping=OpenMutex(MUTEX_ALL_ACCESS,true,"mutex");HANDLE hMapping=OpenFileMapping(FILE_MAP_ALL_ACCESS,NULL,"map");if (hMapping==INVALID_HANDLE_VALUE){printf("error\n");}HANDLE semEmpty =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"EMPTY");HANDLE semFull =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"FULL");for (int i = 0; i < 6; i++){WaitForSingleObject(semEmpty, INFINITE);SYSTEMTIME st;GetSystemTime(&st);srand((unsigned)time(0));Sleep(rand()/6);WaitForSingleObject(hMutexMapping,INFINITE);LPVOID pFile=MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,0);if (pFile!=NULL){struct buf *pnData=reinterpret_cast<struct buf *>(pFile);pnData->buffer[pnData->write]=1;pnData->write=(pnData->write+1)%3;pnData->num++;printf("%02d:%02d:%02d 生产者[%d]生产成功缓冲区中剩余%d个 ",st.wHour,st.wMinute,st.wSecond,n,pnData->num);for (j = 0; j < 3; j++){printf("%d ",pnData->buffer[j]);}printf("\n");}UnmapViewOfFile(pFile);pFile=NULL;ReleaseSemaphore(semFull, 1, NULL);ReleaseMutex(hMutexMapping);}printf("生产者[%d]生产完毕\n",n);}void Consumer(int n){int j;printf("Consumer is running.\n");hMutexMapping=OpenMutex(MUTEX_ALL_ACCESS,true,"mutex");HANDLE hMapping=OpenFileMapping(FILE_MAP_ALL_ACCESS,NULL,"map");if (hMapping==INVALID_HANDLE_VALUE){printf("error\n");}HANDLE semEmpty =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"EMPTY");HANDLE semFull =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"FULL");for (int i = 0; i < 4; i++){WaitForSingleObject(semFull, INFINITE);SYSTEMTIME st;GetSystemTime(&st);srand((unsigned)time(0));Sleep(rand()/6);WaitForSingleObject(hMutexMapping,INFINITE);LPVOID pFile=MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,0);if (pFile!=NULL){struct buf *pnData=reinterpret_cast<struct buf *>(pFile);pnData->buffer[pnData->read]=0;pnData->read=(pnData->read+1)%3;pnData->num--;printf("%02d:%02d:%02d 消费者[%d]消费成功缓冲区中剩余%d个 ",st.wHour,st.wMinute,st.wSecond,n,pnData->num);for (j = 0; j < 3; j++){printf("%d ",pnData->buffer[j]);}printf("\n");}UnmapViewOfFile(pFile);pFile=NULL;ReleaseSemaphore(semEmpty,1,NULL);ReleaseMutex(hMutexMapping);}printf("消费者[%d]消费完毕\n",n);}int main(int argc,char **argv){if (argc>1&&strcmp(argv[1],"productor")==0){Productor(atoi(argv[2]));}else if (argc>1&&strcmp(argv[1],"consumer")==0){Consumer(atoi(argv[2]));}else{Parent();WaitForMultipleObjects(num,lpHandle,true,INFINITE); }return 0;}Linux下代码:Windows运行截图:Linux下截图:。
嵌入式操作系统Linux实验报告专业:计算机科学与技术班级:13419011学号:1341901124姓名:武易组员:朱清宇实验一Linux下进程的创建一实验目的1.掌握Linux下进程的创建及退出操作2.了解fork、execl、wait、waitpid及之间的关系二实验内容创建进程,利用fork函数创建子进程,使其调用execl函数,退出进程后调用wait或waitpid清理进程。
三实验过程1.进程的创建许多进程可以并发的运行同一程序,这些进程共享内存中程序正文的单一副本,但每个进程有自己的单独的数据和堆栈区。
一个进程可以在任何时刻可以执行新的程序,并且在它的生命周期中可以运行几个程序;又如,只要用户输入一条命令,shell进程就创建一个新进程。
fork函数用于在进程中创建一个新进程,新进程是子进程。
原型如下:#include<sys/types.h> /* 提供类型pid_t的定义 */#include<unistd.h> /* 提供函数的定义 */pid_t fork(void);使用fork函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间fork系统调用为父子进程返回不同的值,fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:在父进程中,fork返回新创建子进程的进程ID;✓在子进程中,fork返回0;✓如果出现错误,fork返回一个负值;用fork创建子进程后执行的是和父进程相同的程序,子进程可以通过调用exec函数以执行另一个程序。
当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程(例如其m a i n函数)开始执行。
调用e x e c并不创建新进程,进程I D并未改变,只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。
e x e c函数原型execl,execlp,execle,execv,execve和execvp2.进程的退出一个进程正常终止有三种方式:由main()函数返回;调用exit()函数;调用_exit()或_Exit()函数。
#include<stdio.h>#include<pthread.h>#define MAX 30#define BUFFER_SIZE 20pthread_mutex_t the_mutex,the_main,the_p;pthread_cond_t condc,condp;int buffer[BUFFER_SIZE];int in=0;int out=0;int counter=0;int flg[30]={0};int k=0;int p=0;void *producer1(void* s){pthread_mutex_lock(&the_main);pthread_mutex_unlock(&the_main);int proid=(int)s;int i;for(i=1;i<=MAX;i++){pthread_mutex_lock(&the_mutex);while(counter==BUFFER_SIZE){printf("%d号生产者wait...\n",proid);pthread_cond_wait(&condp,&the_mutex);printf("%d号生产者唤醒...\n",proid);}buffer[in]=1;printf("%d号生产者生产1放入%d中\n",proid,in);in=(in+1)%BUFFER_SIZE;counter++;pthread_cond_signal(&condc);pthread_mutex_unlock(&the_mutex);}pthread_mutex_lock(&the_p);p++;printf("%d号生产者线程结束\n",proid);pthread_mutex_unlock(&the_p);return 0;}void *consumer1(void* s){pthread_mutex_lock(&the_main);pthread_mutex_unlock(&the_main);int conid=(int)s;int j=1;int k=0;while(1){pthread_mutex_lock(&the_mutex);if(p==30&&counter==0){pthread_mutex_unlock(&the_mutex);break;}// printf("p=%d counter=%d\n",p,counter);while(counter==0){if(p==30&&counter==0){pthread_mutex_unlock(&the_mutex);break;}printf(" %d号消费者wait...\n",conid); pthread_cond_wait(&condc,&the_mutex);printf("%d号消费者唤醒...\n",conid);}if(buffer[out]==4){printf("%d号消费者在%d处消费%d counter=%d p=%d\n",conid,out);buffer[out]=0;out=(out+1)%BUFFER_SIZE;counter--;pthread_cond_signal(&condp);}if(buffer[out]==1&&flg[conid]==0){flg[conid]=1;printf("%d号消费者在%d处消费%d counter=%d p=%d\n",conid,out);for(j=1;j<=29;j=j+2)if(flg[j]==1)k++;if(k==15){k=0;for(j=1;j<=29;j++)flg[j]=0;buffer[out]=0;out=(out+1)%BUFFER_SIZE;counter--;pthread_cond_signal(&condp);}elsek=0;}else{pthread_cond_signal(&condc);}pthread_mutex_unlock(&the_mutex);}printf("%d消费者线程结束\n",conid);pthread_exit(0);}int main(int argc,char **argv){int j;pthread_t pro[31],con[31];pthread_mutex_init(&the_mutex,0);pthread_mutex_init(&the_main,0);pthread_cond_init(&condc,0);pthread_cond_init(&condp,0);pthread_mutex_lock(&the_main);for(j=1;j<=10;j=j+2){pthread_create(&pro[j],0,producer1,(void*)j);pthread_create(&con[j],0,consumer1,(void*)j);}printf("线程创建完成\n");pthread_mutex_unlock(&the_main);for(j=1;j<=30;j++){pthread_join(con[j],0);}printf("消费者线程结束\n");pthread_mutex_destroy(&the_main);pthread_cond_destroy(&condc);pthread_cond_destroy(&condp);pthread_mutex_destroy(&the_mutex);。
linux生产消费者模型的c语言实现概述及解释说明1. 引言1.1 概述本篇文章旨在介绍Linux生产者-消费者模型的C语言实现,并对其进行解释说明。
生产者-消费者模型是一种常见的多线程编程模型,用于处理共享数据的并发访问。
该模型通过将任务分为生产者和消费者两类角色来协调线程之间的工作,提高系统的性能和效率。
1.2 文章结构本文将按照以下顺序来讲解Linux生产者-消费者模型的C语言实现:- 引言:介绍本文的目的、内容和结构。
- 生产者-消费者模型:详细解释什么是生产者-消费者模型以及在Linux中的应用场景。
同时探讨该模型的优势和局限性。
- C语言实现生产者-消费者模型:介绍使用互斥锁和条件变量进行线程同步的方法,并讨论线程创建与销毁过程中需要注意的事项。
此外,还会涉及队列数据结构设计与实现方法。
- 示例代码演示与解读说明:展示完整示例代码,并逐行对其进行详细解读说明。
同时介绍如何运行结果分析以及问题排查技巧。
- 结论与展望:总结文章主要研究成果,探讨生产者-消费者模型的发展趋势和可能的改进方向,并对整篇文章进行总结。
1.3 目的本文旨在帮助读者理解Linux生产者-消费者模型的基本概念和原理,并提供具体实现方法。
通过示例代码的演示和解析,读者将能够掌握线程同步机制、队列数据结构以及运行结果分析等相关技术。
同时,为了深入了解该模型在实际应用中可能遇到的问题,本文还会介绍一些问题排查技巧。
通过阅读本文,读者将能够更好地应用生产者-消费者模型来优化自己的程序设计和开发工作。
2. 生产者-消费者模型:2.1 什么是生产者-消费者模型:生产者-消费者模型是一种常见的并发编程模式,用于解决多线程环境下的生产者和消费者之间的数据共享与同步问题。
在该模型中,生产者负责生成数据并将其放入共享区域,而消费者则从共享区域中获取数据进行处理。
通过这种方式,可以实现不同线程之间的解耦和协作。
2.2 在Linux中的应用场景:在Linux操作系统中,生产者-消费者模型得到广泛应用。
中南大学操作系统实验报告实验内容:Java多线程模拟生产者消费者问题实验时间:2014年5月指导老师:胡小龙老师姓名:代巍班级:信安1201班学号:**********一、实验目的对操作系统的整体进行一个模拟,通过实践加深对各个部分的管理功能的认识,还能进一步分析各个部分之间的联系,最后达到对完整系统的理解。
可以提高运用操作系统知识解决实际问题的能力;锻炼实际的编程能力,要达到以下要求。
(1)掌握进程(线程)的同步与互斥。
(2)掌握生产者消费者问题的实现方法。
(3)掌握多线程编程方法。
二、实验内容实现生产者消费者问题。
(1)假设循环缓冲队列共有多个缓冲单元。
(2)生产者线程的工作:生产出一个产品(即产生一个产品编号),按顺序往缓冲队列中“空”的缓冲单元放产品。
(3)消费者线程与的工作:从缓冲队列装有产品的缓冲单元中取出一个产品(即产品编号)。
(4)保证两个线程间的互斥和同步(5)在界面上打印缓冲队列的变化情况三、实验原理(1)生产者—消费者问题是一种同步问题的抽象描述。
(2)计算机系统中的每个进程都可以消费或生产某类资源。
当系统中某一进程使用某一资源时,可以看作是消耗,且该进程称为消费者。
(3)而当某个进程释放资源时,则它就相当一个生产者。
模式还需要有一个缓冲区处于生产者和消费者之间,作为一个中介。
生产者把数据放入缓冲区,而消费者从缓冲区取出数据。
大概的结构如下图。
四、实验思想概述在操作系统中,线程有时被称为轻量级进程,是CPU使用的基本单位,它与属于同一进程的其他进程共享其他代码段、数据段和其他操作系统资源。
在Java中,线程的建立有两种方法:继承Thread类和实现Runnable接口。
其中,采用实现Runnable接口建立线程的好处是允许同时继承其他类从而实现多继承,并且在Java中,可采用synchronized或Object类的方法wait(),notify(),notifyAll()来实现多线程同步。
操作系统实验报告操作系统是计算机科学中十分重要的一门课程,本次实验是关于操作系统的,通过实验,我们可以更深入地了解操作系统的相关知识和操作。
本篇文章将着重介绍本次操作系统实验的内容和实验过程中的收获。
一、实验内容本次实验内容主要涉及操作系统的进程、线程和进程同步三部分。
具体内容包括:1. 进程的创建和管理2. 线程的创建和管理3. 进程同步的实现在实验过程中,我们将分别使用C语言和Linux操作系统实现上述功能。
二、实验过程1. 进程的创建和管理在这一部分实验中,我们要创建多个进程,实现进程的调度和管理功能。
我们采用了Linux系统下的fork()函数,用于创建子进程。
在程序运行时,首先创建一个父进程,然后使用fork()函数创建四个子进程,每个子进程都有自己的进程号(pid),并在屏幕上输出该进程号以示区分。
为了实现进程的调度功能,我们在代码中加入了sleep()函数,用于将进程挂起一段时间,然后再轮流执行其他进程。
2. 线程的创建和管理在这一部分实验中,我们使用了C语言的POSIX线程库pthread.h,实现多线程的功能。
同样地,我们采用了Linux系统下的fork()函数来创建线程。
在代码运行时,我们创建了两个线程,并在屏幕上输出线程号(tid)以示区分。
为了实现线程的调度和管理功能,我们在代码中加入了pthread_join()函数,用于等待线程的执行完成。
3. 进程同步的实现在这一部分实验中,我们使用了Linux系统下的进程同步工具——信号量(semaphore)。
在代码中,我们使用sem_init()函数创建信号量,使用sem_wait()函数阻塞进程或线程,使用sem_post()函数释放进程或线程。
为了更好地理解信号量的工作原理,我们将代码分为生产者和消费者两部分,其中生产者用于向缓冲区添加数据,消费者则用于删除数据。
在这个过程中,我们需要使用信号量控制生产者和消费者的数量,避免出现生产过多或消费过多的情况。
Linux实验报告姓名黄芳恺班级软件工程114学号119074258指导教师阮越目录实验一Linux基本命令的使用实验二简单Shell程序设计实验三Linux下简单C程序设计与文件操作实验四Linux下进程操作与进程间通信实验五Linux线程的使用实验六Linux进程间的IPC实验七Linux下访问Mysql数据库实验八Linux下网络编程练习题:grep、bash、生产者消费者实验一Linux基本命令的使用1、实验目的学习和掌握Linux的基本命令。
2、实验内容和步骤步骤1:以user_login用户身份并使用telnet登录Linux服务器,按照提示创建自己的账户和口令。
步骤2:使用新创建的用户账户和口令登录Linux系统,察看登录后的界面。
步骤3:使用pwd命令察看当前的工作目录,然后用ls命令查看当前目录下的内容,尝试使用-a,-l,-F,-A,-lF等不同选项并比较不同之处。
-a do not ignore entries starting with-I, --ignore=PATTERN do not list implied entries matching shell PATTERN -l use a long listing format-F, --classify append indicator (one of */=>@|) to entries-A, --almost-all do not list implied . and ..-lF ignore file步骤4:在当前目录下建立一个名为test的新目录,然后将工作目录切换到test下,尝试将/etc目录下的文件passwd拷贝到该目录下(cp 源文件目的目录)。
察看当前目录下的passwd文件的属主和文件权限。
步骤5:尝试向当前目录下的passwd文件和/etc/passwd文件分别写入一些新内容(可使用echo “字符串”>>文件的命令),看看操作能否成功,如果不能成功,请说明原因。
1.互斥#include <stdio.h>#include <pthread.h>#define BUFFER_SIZE 4#define OVER (-1)struct producers//定义生产者条件变量结构{int buffer[BUFFER_SIZE]; //定义缓冲区pthread_mutex_t lock; //访问缓冲区的互斥锁int readpos, writepos; //读写的位置pthread_cond_t notempty; //缓冲区有数据时的标记pthread_cond_t notfull; //缓冲区未满的标记};//初始化缓冲区void init(struct producers *b) //参数即为一个结构体,要struct,//定义时不用typedef{pthread_mutex_init(&b->lock,NULL);pthread_cond_init(&b->notempty,NULL);pthread_cond_init(&b->notfull,NULL); //初始化相关量b->readpos=0;b->writepos=0;//开始位置都为0}//在缓冲区存放一个整数void put(struct producers *b, int data) //两个参数,其中一个为数据{pthread_mutex_lock(&b->lock); //在put函数中完成互斥//当缓冲区为满时等待while((b->writepos+1)%BUFFER_SIZE==b->readpos)//满的条件是两个游标相邻{pthread_cond_wait(&b->notfull,&b->lock);}//在返回之前,pthread_con_wait需要参数b.lockb->buffer[b->writepos]=data; //否则在写的位置写入数据b->writepos++;//游标加一if(b->writepos>=BUFFER_SIZE) b->writepos=0; //满时,写位置置0 //发送当前缓冲区中有数据的信号pthread_cond_signal(&b->notempty);//pthread_mutex_unlock(&b->lock);}//从缓冲区读数据并将数据移走int get(struct producers *b){int data;pthread_mutex_lock(&b->lock);while(b->writepos==b->readpos)//此时无数据可读,阻塞{pthread_cond_wait(&b->notempty,&b->lock);}data=b->buffer[b->readpos]; //否则读数据b->readpos++;if(b->readpos>=BUFFER_SIZE) b->readpos=0;pthread_cond_signal(&b->notfull);pthread_mutex_unlock(&b->lock);return data;//返回读的数据}struct producers buffer;//事先要定义这个全局变量void *producer(void *data) //参数应该为void,与上面的data无关{int n;for(n=0;n<10;n++){printf("Producer : %d-->\n",n);put(&buffer,n);}put(&buffer,OVER);return NULL;}void *consumer(void *data){int d;while(1){d=get(&buffer);if(d==OVER) break;printf("Consumer: --> %d\n",d);}return NULL;}int main(){pthread_t tha,thb;void *retval;init(&buffer);pthread_create(&tha,NULL,producer,0);pthread_create(&thb,NULL,consumer,0);pthread_join(tha,&retval);pthread_join(thb,&retval);return 0;}2.用条件变量#include<stdio.h>#include<pthread.h>#define BUFFER_SIZE 8#define OVER (-1)struct producers {//定义生产者条件变量结构int buffer[BUFFER_SIZE]; //缓冲区pthread_mutex_t lock; //互斥LOCKint readpos , writepos; //读写位置pthread_cond_t notempty; //缓冲区非空条件判断pthread_cond_t notfull; //缓冲区未满条件判断};void init(struct producers * b){//初始化缓冲区pthread_mutex_init(&b->lock,NULL);pthread_cond_init(&b->notempty,NULL);pthread_cond_init(&b->notfull,NULL);b->readpos=0;b->writepos=0;}//缓冲区刚开始的情况void put(struct producers * b,int data){//缓冲区中放入一个数据pthread-_mutex_lock(&b->lock);//当缓冲区为满时等待,即写的位置前移一个就是写的位置了if((b->writepos + 1) % BUFFER_SIZE == b->readpos){pthread_cond_wait(&b->notfull, &b->lock) ;//此时已满,要等信号notfull才能写。