1、linux多线程实验报告实验八 Linux多线程实验报告撰写人专业班级学号完成时间。一、实验目的1、了解什么是多线程,熟悉LINUX的多线程机制;2、掌握利用信号处理Linux多线程的同步问题;3、掌握利用信号量处理Linux多线程的互斥问题;4、运用Linux多线程的同步机制和互斥机制实现生产者消费者的编程。二、实验内容1“生产者-消费者”问题如下:有一个有限缓冲区和两个线程:生产者和消费者。他们分别不停地把产品放入缓冲区、从缓冲区中拿走产品。一个生产者在缓冲区满的时候必须等待,一个消费者在缓冲区空的时候也必须等待。另外,因为缓冲区是临界资源,所以生产者和消费者之间必须互斥执行。它们之间的关
2、系如图1所示。现在要求使用共享内存来模拟有限缓冲区,并且使用信号量来解决“生产者-消费者”问题中的同步和互斥问题。1 生产者和消费者问题描述2. 问题描述:假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。请用Linux线程编程解决。2 哲学家进餐问题示意图三、实验过程与结果操作过程错误解决方法实验1步骤一:编写producer_customer.c的文件在不
3、同的编译器中for循环的用法不太一样,在这里最好不要使用for(int i=0; ;)最好在外声明int i在for循环里直接写i=0步骤二:编译代码并且运行代码步骤三:运行完毕后,显示以下代码:生产者消费者先后生产数据以及取出数据,此程序中设置了两个消费者两个生产者,交替进行生产数据消费数据。实验2步骤一:编写philosopher.c的文件步骤二:编译代码并且运行代码步骤三:实验代码实验一:#include #include #include #include #include #include #include #include #define MAX_BUFFER_SIZE 10#de
4、fine SHM_MODE 0600#define SEM_MODE 0600#define SEM_FULL 0#define SEM_EMPTY 1#define MUTEX 2/*#if defined(_GNU_LIBRARY_) & !defined(_SEM_SEMUN_UNDEFINED)/ union semun is defined by including #else/ according to X/OPEN we have to define it ourselvesunion semunint val;struct semid_ds *buf;unsigned shor
5、t *array;#endifunion semun su;/sem union,用于初始化信号量*/struct my_buffer int head; int tail; char strMAX_BUFFER_SIZE; int num; /缓冲区里字母数量 int is_empty;const int N_CONSUMER = 2;/消费者数量const int N_PRODUCER = 2;/生产者数量const int N_BUFFER = 10;/缓冲区容量const int N_WORKTIME = 10;/工作次数int shm_id = -1;int sem_id = -1;
6、pid_t child;pid_t parent;/得到10以内的一个随机数int get_random() int digit; srand(unsigned)(getpid() + time(NULL); digit = rand() % 10; return digit;/得到AZ的一个随机字母char getRandChar() char letter; srand(unsigned)(getpid() + time(NULL); letter = (char)(rand() % 26) + A); return letter;/sem_id 表示信号量集合的 id/sem_num 表
7、示要处理的信号量在信号量集合中的索引/P操作void waitSem(int sem_id,int sem_num) struct sembuf sb; sb.sem_num = sem_num; sb.sem_op = -1;/表示要把信号量减一 sb.sem_flg = SEM_UNDO;/第二个参数是 sembuf 类型的,表示数组/第三个参数表示 第二个参数代表的数组的大小 if(semop(sem_id,&sb,1) 0) perror(waitSem failed); exit(1); /V操作void sigSem(int sem_id,int sem_num) struct s
8、embuf sb; sb.sem_num = sem_num; sb.sem_op = 1; sb.sem_flg = SEM_UNDO; /第二个参数是 sembuf 类型的,表示数组 /第三个参数表示 第二个参数代表的数组的大小 if(semop(sem_id,&sb,1) 0) perror(sigSem failed); exit(1); /打印进程运行结果void printTime() /打印时间 time_t now; struct tm *timenow; /实例化tm结构指针 time(&now); timenow = localtime(&now); printf(执行时间
9、: %s ,asctime(timenow);int main(int argc, char * argv) shm_id = shmget(IPC_PRIVATE,MAX_BUFFER_SIZE,SHM_MODE); /申请共享内存 if(shm_id 0) perror(create shared memory failed); exit(1); struct my_buffer *shmptr; shmptr = shmat(shm_id, 0, 0); /将申请的共享内存附加到申请通信的进程空间 if (shmptr = (void*)-1) perror(add buffer to
10、using process space failed!n); exit(1); if(sem_id = semget(IPC_PRIVATE,3,SEM_MODE) SEM_FULL perror(sem set value error! n); exit(1); if(semctl(sem_id,SEM_EMPTY,SETVAL,10) = -1) /将索引为1的信号量设置为10-SEM_EMPTY perror(sem set value error! n); exit(1); if(semctl(sem_id,MUTEX,SETVAL,1) = -1) /将索引为3的信号量设置为1-MU
11、TEX perror(sem set value error! n); exit(1); shmptr - head = 0; shmptr - tail = 0; shmptr - is_empty = 1; shmptr - num = 0; int i; for(i = 0; i N_PRODUCER; i+) parent = fork(); if(parent 0) perror(the fork failed); exit(1); else if(parent = 0) shmptr = shmat(shm_id, 0, 0); /将申请的共享内存附加到申请通信的进程空间 if (
12、shmptr = (void*)-1) perror(add buffer to using process space failed!n); exit(1); int count = 0; int j; for(j = 0; j strshmptr-tail = c; shmptr - tail = (shmptr-tail + 1) % MAX_BUFFER_SIZE; shmptr - is_empty = 0; /写入新产品 shmptr - num+; /*打印输出结果*/ printTime(); /程序运行时间 int p; printf(缓冲区数据(%d个):,shmptr -
13、 num); /打印缓冲区中的数据 p = (shmptr-tail-1 = shmptr-head) ? (shmptr-tail-1) : (shmptr-tail-1 + MAX_BUFFER_SIZE); for (p; !(shmptr - is_empty) & p = shmptr - head; p-) printf(%c, shmptr - strp % MAX_BUFFER_SIZE); printf(t 生产者 %d 放入 %c. n, i + 1, c); printf(-n); fflush(stdout); sigSem(sem_id, MUTEX); sigSem
14、(sem_id, SEM_FULL); /将共享段与进程之间解除连接 shmdt(shmptr); exit(0); for(i = 0; i N_CONSUMER; i+) child = fork(); if(child 0)/调用fork失败 perror(the fork failed); exit(1); else if(child = 0) int count = 0; shmptr = shmat(shm_id, 0, 0); /将申请的共享内存附加到申请通信的进程空间 if (shmptr = (void*)-1) perror(add buffer to using proc
15、ess space failed!n); exit(1); int j; for(j = 0; j strshmptr - head; shmptr - head = (shmptr - head + 1) % MAX_BUFFER_SIZE; shmptr - is_empty = (shmptr-head = shmptr-tail); / shmptr - num-; /*打印输出结果*/ printTime(); /程序运行时间 int p; printf(缓冲区数据(%d个):,shmptr - num); /打印缓冲区中的数据 p = (shmptr - tail - 1 = sh
16、mptr - head) ? (shmptr - tail-1) : (shmptr - tail - 1 + MAX_BUFFER_SIZE); for (p; !(shmptr - is_empty) & p = shmptr - head; p-) printf(%c, shmptr - strp % MAX_BUFFER_SIZE); printf(t 消费者 %d 取出 %c. n, i + 1, lt); printf(-n); fflush(stdout); sigSem(sem_id,MUTEX); sigSem(sem_id,SEM_EMPTY); /将共享段与进程之间解除连
17、接 shmdt(shmptr); exit(0); /主进程最后退出 while (wait(0) != -1); /将共享段与进程之间解除连接 shmdt(shmptr); /对共享内存区执行控制操作 shmctl(shm_id,IPC_RMID,0);/当cmd为IPC_RMID时,删除该共享段 shmctl(sem_id,IPC_RMID,0); printf(主进程运行结束!n); fflush(stdout); exit(0); return 0;实验二:#include#include#include#include#include#include#include#define N
18、 5 /哲学家数量#define LEFT(i) (i+N-1)%N /左手边哲学家编号#define RIGHT(i) (i+1)%N /右手边哲家编号#define HUNGRY 0 /饥饿#define THINKING 1 /思考#define EATING 2 /吃饭#define U_SECOND 1000000 /1秒对应的微秒数pthread_mutex_t mutex; /互斥量int stateN; /记录每个哲学家状态/每个哲学家的思考时间,吃饭时间,思考开始时间,吃饭开始时间clock_t thinking_timeN, eating_timeN, start_eati
19、ng_timeN, start_thinking_timeN; /线程函数void *thread_function(void *arg);int main() pthread_mutex_init(&mutex, NULL); pthread_t a,b,c,d,e; /为每一个哲学家开启一个线程,传递哲学家编号 pthread_create(&a,NULL,thread_function,0); pthread_create(&b,NULL,thread_function,1); pthread_create(&c,NULL,thread_function,2); pthread_crea
20、te(&d,NULL,thread_function,3); pthread_create(&e,NULL,thread_function,4); /初始化随机数种子 srand(unsigned int)(time(NULL); while(1) ; void *thread_function(void *arg) char *a = (char *)arg; int num = a0 - 0; /根据传递参数获取哲学家编号 int rand_time; while(1) /关键代码加锁 pthread_mutex_lock(&mutex); /如果该哲学家处于饥饿 并且 左右两位哲学家都没
21、有在吃饭 就拿起叉子吃饭 if(statenum = HUNGRY & stateLEFT(num) != EATING & stateRIGHT(num) != EATING) statenum = EATING; start_eating_timenum = clock(); /记录开始吃饭时间 eating_timenum = (rand() % 5 + 5) * U_SECOND; /随机生成吃饭时间 /输出状态 printf(state: %d %d %d %d %dn,state0,state1,state2,state3,state4); /printf(%d is eating
22、n,num); else if(statenum = EATING) /吃饭时间已到 ,开始思考 if(clock() - start_eating_timenum = eating_timenum) / statenum = THINKING; /printf(%d is thinkingn,num); printf(state: %d %d %d %d %dn,state0,state1,state2,state3,state4); start_thinking_timenum = clock(); /记录开始思考时间 thinking_timenum = (rand() % 10 + 1
23、0) * U_SECOND; /随机生成思考时间 else if(statenum = THINKING) /思考一定时间后,哲学家饿了,需要吃饭 if(clock() - start_thinking_timenum = thinking_timenum) statenum = HUNGRY; printf(state: %d %d %d %d %dn,state0,state1,state2,state3,state4); / printf(%d is hungryn,num); pthread_mutex_unlock(&mutex); 四、实验小结生产者消费者问题(英语:Produce
24、r-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程即所谓的“生产者”和“消费者”在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。1) 关系分析。生产者和消费者对缓冲区互斥访问是互斥关系,同时生产者和消费者又是一个相互协作的关系,只有生产者生产之后,消费者才能消费,他们也是同步关系。2) 整理思路。这里比较简单,只有生产者和消费者两个进程,正好是这两个进程存在着互斥关系和同步关系。那么需要解决的是互斥和同步PV操作的位置。3) 信号量设置。信号量mutex作为互斥信号量,它用于控制互斥访问缓冲池,互斥信号量初值为1;信号量full用于记录当前缓冲池中“满”缓冲区数,初值为0。信号量empty 用于记录当前缓冲池中“空”缓冲区数,初值为n。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1