Linux基础练习_多线程

【问题描述】

Fast-food restaurant problem: Design, implement and test a solution for

the IPC problem specified below. Suppose we have the following scenario:

 50 customers successively come to a fast-food restaurant to buy some food. They have

different IDs.

 The intervals between two customers are random: 1, 2, 3, 4 or 5 minutes.

 Customers join in one FIFO queue after arriving at the restaurant, called queue1, and

wait to be served by the foreman one by one.

 To serve customers, the foreman asks customers to order dishes one by one, writes

them down in papers and submits these orders with customer IDs. After that,

customers will be de-queued from queue1 and join in another queue called queue2,

waiting for their dishes.

 There are 3 cooks, and each one can undertake one order at a time. As long as they are

idle and there are any orders, they will undertake them and finish them.

 Each cook can finish one order in a random time: 3, 4 or 5 minutes.

 Each order corresponds to a meal, which may contain several dishes. But for simplicity,

you can just call it a "dish".

 Each dish(meal) has the same ID as the corresponding order.

 All the dishes will be put in a box with a limited size to keep warm. The box can contain

at most 10 dishes(meals).

 The cashier will take the dishes from the box one by one and offer them to

corresponding customers. For the sake of simplicity, you can also see the box as a

queue.

 The cashier calls out the dish ID, and finds the corresponding customer. This customer

pays the money and the cashier offers the dishes at the same time. For simplicity, you

can suppose either action prior to the other.

 Since time to cook dishes is not equal, the queue2 is not an FIFO queue.

 To save time, one second in the program represents one minute in this scenario.

--------------------------------------------------------------------------------------------------------------------

Tips:

 The customers can be expressed by only 2 threads instead of 50 ones because at the

same time only one customer will be served in one queue. On the contrary, 3 cooks can

work simultaneously, so three threads generated from the same copy of thread_cooks()

function are needed.

 To send wake-up signal to the three cook threads, the "pthread_cond_broadcast"

function is needed.

 In the implemented code we use the "malloc" function to build each queue. Moreover,

we set the size of each queue to be 50 except the box, which is equal to the total

number of customers. So customer "i" will be stored exactly at the location "i", and no

element will be moved.The size of food box should exactly be 10.

【我的解答】

header.h

#ifndef H_header
#define H_header

#define RED "\033[1;32;31m"
#define GREEN "\033[1;32;32m"
#define BLUE "\033[1;32;34m"
#define YELLOW "\033[1;33m"
#define WHITE "\033[1;37m"

#include <semaphore.h>
#include <pthread.h>

extern int max_number_of_customers; //The total number of customers in this program

extern sem_t number_of_customers_in_queue1, number_of_customers_in_queue2;
extern pthread_mutex_t mutex_queue1, mutex_queue2; //To make sure each role gets access to both queues of customers mutually exclusively
extern struct customer{ int id; } *queue_customer_1, *queue_customer_2;
extern int number_of_customers_waiting_in_queue1; //A variable which is just used to test conditional variable

extern pthread_mutex_t mutex_of_order; //To make sure each role gets access to the queue of orders mutually exclusively
extern struct order{ int id; } *queue_order;
extern pthread_cond_t cond_customers_in_queue1; //If no customers are in queue1, the foreman will block himself
extern int number_of_orders_to_be_finished; //A variable which is just used to test conditional variable

extern pthread_mutex_t mutex_of_dishes;
extern pthread_cond_t cond_orders, cond_rooms_for_dishes;
extern int dishes_full, dishes_empty;
extern struct dishes{ int id; } *queue_dishes;
extern int number_of_orders_received;

extern pthread_mutex_t mutex_dishes_offered_id;
extern pthread_cond_t cond_dishes, cond_payment, cond_offer;
extern int dishes_offered_id;

extern void Initialize();
extern void Destroy();

#endif

header.c

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>

#include "header.h"

int max_number_of_customers = 50;
sem_t number_of_customers_in_queue1, number_of_customers_in_queue2;
pthread_mutex_t mutex_queue1, mutex_queue2; //To make sure each role gets access to both queues of customers mutually exclusively
struct customer *queue_customer_1, *queue_customer_2;
int number_of_customers_waiting_in_queue1 = 0; //A variable which is just used to test conditional variable

pthread_mutex_t mutex_of_order; //To make sure each role gets access to the queue of orders mutually exclusively
struct order *queue_order;
pthread_cond_t cond_customers_in_queue1; //If no customers are in queue1, the foreman will block himself
int number_of_orders_to_be_finished = 0; //A variable which is just used to test conditional variable

pthread_mutex_t mutex_of_dishes;
pthread_cond_t cond_orders, cond_rooms_for_dishes;
int dishes_full = 0, dishes_empty = 10;
struct dishes *queue_dishes;
int number_of_orders_received = 0;

pthread_mutex_t mutex_dishes_offered_id;
pthread_cond_t cond_dishes, cond_payment, cond_offer;
int dishes_offered_id = -1;

void Initialize(){
	/*Initialize semaphores, mutexes and conditional variables*/
	int returnvalue;

	returnvalue = sem_init(&number_of_customers_in_queue1, 0, 0);
	if(returnvalue == -1){
		printf("Semaphore number_of_customers_in_queue1 initialization failed!\n");
		exit(-1);
	}

	returnvalue = sem_init(&number_of_customers_in_queue2, 0, 0);
	if(returnvalue == -1){
		printf("Semaphore number_of_customers_in_queue2 initialization failed!\n");
		exit(-1);
	}

	returnvalue = pthread_mutex_init(&mutex_queue1, 0);
	if(returnvalue != 0){
		printf("Mutex mutex_queue1 initialization failed!\n");
		exit(-1);
	}

	returnvalue = pthread_mutex_init(&mutex_queue2, 0);
	if(returnvalue != 0){
		printf("Mutex mutex_queue2 initialization failed!\n");
		exit(-1);
	}

	returnvalue = pthread_mutex_init(&mutex_of_order, 0);
	if(returnvalue != 0){
		printf("Mutex mutex_of_order initialization failed!\n");
		exit(-1);
	}

	returnvalue = pthread_mutex_init(&mutex_of_dishes, 0);
	if(returnvalue != 0){
		printf("Mutex mutex_of_dishes initialization failed!\n");
		exit(-1);
	}

	returnvalue = pthread_mutex_init(&mutex_dishes_offered_id, 0);
	if(returnvalue != 0){
		printf("Mutex mutex_dishes_offered_id initialization failed!\n");
		exit(-1);
	}

	returnvalue = pthread_cond_init(&cond_customers_in_queue1, 0);
	if(returnvalue != 0){
		printf("Condition variable cond_customers_in_queue1 initialization failed!\n");
		exit(-1);
	}

	returnvalue = pthread_cond_init(&cond_orders, 0);
	if(returnvalue != 0){
		printf("Condition variable cond_orders initialization failed!\n");
		exit(-1);
	}

	returnvalue = pthread_cond_init(&cond_rooms_for_dishes, 0);
	if(returnvalue != 0){
		printf("Condition variable cond_rooms_for_dishes initialization failed!\n");
		exit(-1);
	}

	returnvalue = pthread_cond_init(&cond_dishes, 0);
	if(returnvalue != 0){
		printf("Condition variable cond_dishes initialization failed!\n");
		exit(-1);
	}

	returnvalue = pthread_cond_init(&cond_payment, 0);
	if(returnvalue != 0){
		printf("Condition variable cond_payment initialization failed!\n");
		exit(-1);
	}

	returnvalue = pthread_cond_init(&cond_offer, 0);
	if(returnvalue != 0){
		printf("Condition variable cond_offer initialization failed!\n");
		exit(-1);
	}

	/*Initialize queues*/
	queue_customer_1 = (struct customer*)malloc(sizeof(struct customer) * 50);
	queue_customer_2 = (struct customer*)malloc(sizeof(struct customer) * 50);
	queue_order = (struct order*)malloc(sizeof(struct order) * 50);
	queue_dishes = (struct dishes*)malloc(sizeof(struct dishes) * 10);

	int i = 0;
	for(;i < 50;i ++){
		queue_customer_1[i].id = queue_customer_2[i].id = queue_order[i].id = -1;
		if(i < 10)queue_dishes[i].id = -1;
	}
}

void Destroy(){
	sem_destroy(&number_of_customers_in_queue1);
	sem_destroy(&number_of_customers_in_queue2);

	pthread_mutex_destroy(&mutex_queue1);
	pthread_mutex_destroy(&mutex_queue2);
	pthread_mutex_destroy(&mutex_of_order);
	pthread_mutex_destroy(&mutex_of_dishes);
	pthread_mutex_destroy(&mutex_dishes_offered_id);

	pthread_cond_destroy(&cond_customers_in_queue1);
	pthread_cond_destroy(&cond_orders);
	pthread_cond_destroy(&cond_rooms_for_dishes);
	pthread_cond_destroy(&cond_dishes);
	pthread_cond_destroy(&cond_payment);
	pthread_cond_destroy(&cond_offer);
}

Question4.c(main函数)

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>

#include "header.h"
#include "Customer.h"
#include "Foreman.h"
#include "Cooks.h"
#include "Cashier.h"

main(){
	Initialize();
	pthread_t customers_come_and_provide_order, customers_pay_and_go, foreman, cook1, cook2, cook3, cashier;
	pthread_create(&customers_come_and_provide_order, 0, thread_customers_come, 0);
	pthread_create(&customers_pay_and_go, 0, thread_customers_go, 0);
	pthread_create(&foreman, 0, thread_foreman, 0);
	pthread_create(&cook1, 0, thread_cooks, 0);
	pthread_create(&cook2, 0, thread_cooks, 0);
	pthread_create(&cook3, 0, thread_cooks, 0);
	pthread_create(&cashier, 0, thread_cashier, 0);

	int returnvalue = pthread_join(customers_pay_and_go, NULL);
	if(returnvalue != 0){
		printf("Errors!\n");
		exit(-1);
	}
	printf(WHITE "All customers have left!\n");

	Destroy();
	return;
}

Foreman.h

#include "header.h"

void *thread_foreman();

Foreman.c

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <semaphore.h>
#include <pthread.h>

#define random(x) (rand() % x)

#include "header.h"
#include "Foreman.h"

void *thread_foreman(){
    int count=0;
    //the foreman must serve 50 customers before he stops working.
    for (; count<max_number_of_customers; count++)
    {
        //Get the exclusive access to 'queue_customer_1', foreman works only if here comes a new customer.
        sem_wait(&number_of_customers_in_queue1);
        pthread_mutex_lock(&mutex_queue1);
        //Serve one customer waiting in the queue1
        queue_customer_1[count].id=-1;
        number_of_customers_waiting_in_queue1 --;
        pthread_mutex_unlock(&mutex_queue1);
        printf(BLUE "The foreman starts serving customer %d!\n", count+1);

        //Get the exclusive access to 'queue_customer_2'
        pthread_mutex_lock(&mutex_queue2);
        queue_customer_2[count].id=count+1;   //The customer joins queue2
        sem_post(&number_of_customers_in_queue2);
        pthread_mutex_unlock(&mutex_queue2);

        //Get the exclusive access to 'queue_order'
        pthread_mutex_lock(&mutex_of_order);
        queue_order[count].id=count+1;    //add a new order to the 'queue_order'
        number_of_orders_to_be_finished++;  //Cooks have a new task to be finished!
        number_of_orders_received=count+1;
        pthread_cond_broadcast(&cond_orders);  //Tell all three cooks to catch the new order.
        pthread_mutex_unlock(&mutex_of_order);
        printf(BLUE "Customer %d has left queue1 and joined in queue2! And his order has been submitted to cooks!\n", count+1);
    }
}

Customer.h

#include "header.h"

void *thread_customers_come();
void *thread_customers_go();

Customer.c

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <semaphore.h>
#include <pthread.h>

#define random(x) (rand() % x)

#include "header.h"
#include "Customer.h"

void *thread_customers_come(){
	int count = 0;
	while(count < max_number_of_customers){
		pthread_mutex_lock(&mutex_queue1); //Get the exclusive access to 'queue_customer_1' and 'number_of_customers_waiting_in_queue1'
		queue_customer_1[count].id = count + 1; //Allocate an ID when each customer is generated
		sem_post(&number_of_customers_in_queue1);

		number_of_customers_waiting_in_queue1 ++; //Add 1 to the semaphore and the testing varaible
		pthread_mutex_unlock(&mutex_queue1);

		printf(RED "One customer comes and joins in the queue1! ID:%d\n", queue_customer_1[count].id);

		count ++;
		sleep(random(5) + 1); //The next customer will come in 1-5 minute(s)
	}

}

void *thread_customers_go(){
	int count = 0;
	while(count < max_number_of_customers){
		pthread_mutex_lock(&mutex_dishes_offered_id); //Get the access to 'dishes_offered_id' exclusively
		pthread_cond_wait(&cond_offer, &mutex_dishes_offered_id); //Wait for the cashier to announce the id and offer the dishes
		printf(RED "The dishes id is %d, and the cashier is ready to receive money and offer dishes!\n", dishes_offered_id);
		/*Find the customer which the dishes belong to*/
		sem_wait(&number_of_customers_in_queue2); //Cut down the number firstly; If this line is between 'pthread_mutex_lock(&mutex_queue2);' and 'pthread_mutex_lock(&mutex_queue2);', it may block forever
		pthread_mutex_lock(&mutex_queue2);
		int i = 0;
		for(;i < 50;i ++){
			if(queue_customer_2[i].id == dishes_offered_id){
				/*Delete the customer from queue_2*/
				queue_customer_2[i].id = -1;
				break;
			}
		}
		pthread_mutex_unlock(&mutex_queue2);
	    pthread_cond_signal(&cond_payment); //The customer pay his money, and wake up the cashier
		printf(RED "Customer %d has paid and got his dishes! He's going to leave!\n", dishes_offered_id);
		pthread_mutex_unlock(&mutex_dishes_offered_id);
		count ++;
	}
}

Cooks.h

#include "header.h"

void *thread_cooks();

Cooks.c

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <semaphore.h>
#include <pthread.h>

#define random(x) (rand() % x)

#include "header.h"
#include "Cooks.h"

void *thread_cooks(){
    while (1)
    {
        //Cooks stop working only if customers reserved have reached the maximum number and there is no more order to be finished at the moment
        if (number_of_orders_received==max_number_of_customers && number_of_orders_to_be_finished==0) break;
        //Get the exclusive access to 'queue_order'
        pthread_mutex_lock(&mutex_of_order);
        //Cooks wait for orders to be finished and try to get one if there is any
        while (number_of_orders_to_be_finished==0) pthread_cond_wait(&cond_orders, &mutex_of_order);
        if (number_of_orders_to_be_finished>0)
        {
            //Catch one order in the queue_order in random
            int i=0;
            for (; i<number_of_orders_received; i++) if (queue_order[i].id>0) break;
            int getId=queue_order[i].id;
            queue_order[i].id=-1;
            number_of_orders_to_be_finished --;  //One order has been received by the cook
            pthread_mutex_unlock(&mutex_of_order);
            printf(YELLOW "Order %d has been received by one cook!\n", getId);

            //Finish the order in 3,4 or 5 minutes
            int temps[3]={3, 4, 5};
            sleep( temps[random(3)] );
            printf(YELLOW "Order %d has been finished!\n", getId);

            //Get the exclusive access to 'queue_dishes'
            pthread_mutex_lock(&mutex_of_dishes);
            //Waiting for room available in the box to put the dish that has been finished by the cook
            while (dishes_empty==0) pthread_cond_wait(&cond_rooms_for_dishes, &mutex_of_dishes);
            if (dishes_empty>0)
            {
                //Choose one space available in random to put the dish
                for (i=0; i<10; i++) if (queue_dishes[i].id<0) break;
                queue_dishes[i].id=getId;
                dishes_empty--;  dishes_full++;
                //Tell the cashier that here comes a new dish and that it should wake up if it is sleeping
                pthread_cond_signal(&cond_dishes);
                pthread_mutex_unlock(&mutex_of_dishes);
            }
        }
    }
}

Cashier.h

#include "header.h"

void *thread_cashier();

Cashier.c

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <semaphore.h>
#include <pthread.h>

#define random(x) (rand() % x)

#include "header.h"
#include "Cashier.h"

void *thread_cashier(){
    int count=0;
    //the cashier must serve 50 customers before he stops working.
    for (; count<max_number_of_customers; count++)
    {
        pthread_mutex_lock(&mutex_of_dishes); //Get the exclusive access to 'queue_dishes'
        //waiting for the cook to finish cooking if there is not any dish
        while (dishes_full==0)  pthread_cond_wait(&cond_dishes, &mutex_of_dishes);

        //get one of the dishes in the box in random
        int i=0;
        for (; i<10; i++) if (queue_dishes[i].id>0) break;
        int getId=queue_dishes[i].id;
        queue_dishes[i].id=-1;
        dishes_full--; dishes_empty++;
        //tell the cooks that there is now space available
        pthread_cond_signal(&cond_rooms_for_dishes);
        pthread_mutex_unlock(&mutex_of_dishes);
        printf(GREEN "The dishes of order %d has been passed to the cashier!\n", getId);

        //Get the exclusive access to 'dishes_offered_id'
        pthread_mutex_lock(&mutex_dishes_offered_id);
        dishes_offered_id=getId;
        pthread_cond_signal(&cond_offer);  //tell the customer_go() that the cashier has offered one dish
        printf(GREEN "The cashier takes out the dishes of customer %d and offer them to the customer!\n", getId);
        pthread_cond_wait(&cond_payment, &mutex_dishes_offered_id);  //waiting for the corresponding customer to pay
        pthread_mutex_unlock(&mutex_dishes_offered_id);
    }
}

MakeFile

Question4: Question4.o header.o Customer.o Foreman.o Cooks.o Cashier.o
	gcc -o Question4 Question4.o header.o Customer.o Foreman.o Cooks.o Cashier.o -pthread

Question4.o: header.h Customer.h Foreman.h Cooks.h Cashier.h
header.o: header.h
Customer.o: header.h Customer.h
Foreman.o: header.h Foreman.h
Cooks.o: header.h Cooks.h
Cashier.o: header.h Cashier.h

clean:
	rm Question4 Question4.o header.o Customer.o Foreman.o Cooks.o Cashier.o

【运行结果】

由于50个客户的运行结果太长,这里截取开头、中间、结尾的结果作说明。

时间: 2024-10-25 06:57:43

Linux基础练习_多线程的相关文章

Linux基础环境_安装配置教程(CentOS7.2 64、JDK1.8、Tomcat8)

Linux基础环境_安装配置教程 (CentOS7.2 64.JDK1.8.Tomcat8) 安装包版本 1)     VMawre-workstation版本包 地址: https://my.vmware.com/web/vmware/details?downloadGroup=WKST-1411-WIN&productId=686&rPId=20814 包名:VMware-workstation-full-12.5.7.20721.exe 2)     CentOS版本包 地址:htt

Linux程序设计学习笔记----多线程编程基础概念与基本操作

转载请注明出处,http://blog.csdn.net/suool/article/details/38542543,谢谢. 基本概念 线程和进程的对比 用户空间资源对比 每个进程在创建的时候都申请了新的内存空间以存储代码段\数据段\BSS段\堆\栈空间,并且这些的空间的初始化值是父进程空间的,父子进程在创建后不能互访资源. 而每个新创建的线程则仅仅申请了自己的栈,空间,与同进程的其他线程共享该进程的其他数据空间包括代码段\数据段\BSS段\堆以及打开的库,mmap映射的文件与共享的空间,使得

python基础教程_学习笔记23:图形用户界面

图形用户界面 丰富的平台 在编写Python GUI程序前,需要决定使用哪个GUI平台. 简单来说,平台是图形组件的一个特定集合,可以通过叫做GUI工具包的给定Python模块进行访问. 工具包 描述 Tkinter 使用Tk平台.很容易得到.半标准. wxpython 基于wxWindows.跨平台越来越流行. PythonWin 只能在Windows上使用.使用了本机的Windows GUI功能. JavaSwing 只能用于Jython.使用本机的Java GUI. PyGTK 使用GTK

linux基础知识第一节

用户接口: 是一种独特的应用程序,能够为用户提供启动其它应用程序的的机制 cli:命令提示符,用户输入要执行的命令即可, shell: 外壳 sh ,csh ,ksh ,   bash, zsh , tcsh gui: 通过点击操作来启动应用程序 gnome,  mainframe  大型机 多用户操作系统    多终端   终端:设备,显示器,鼠标,键盘 虚拟终端 表示:/dev/tty# ctrl-alt-f(1-6) 物理终端(控制终端)console 串行终端 伪终端 /dev/pts#

linux基础知识的总结

例如以下内容是我对linux基础知识的总结,由于本人在初期学习linux的时候走了不少的弯路,对于基础的掌握耗费了不少的时间,所以为了后来者对linux的基础部分有个清晰的了解,特对基础知识进行了总结,由于水平有限.难免有疏忽或者不准确的地方.希望大家可以直接指出来,我会及时改正.一切为了知识的传播.^_^ ? *********************************************************************************************

SEO基础知识_绝密教程

<p align="center"> </p> <p>   </p> <p align="center"> 第一次接触SEO,请阅读本基础指南入门,也可以注册论坛:<a  1-1.html" target="_blank"><span style="color:black;">从一句话入门</span><span s

Linux基础知识--Linux的文件系统和bash的基础特性

Linux基础知识--linux的文件系统和bash的基础特性 一.Linux文件系统: Linux文件系统中的文件是数据的集合,文件系统不仅包含着文件中的数据而且还有文件系统的结构,所有Linux 用户和程序看到的文件.目录.软连接及文件保护信息等都存储在其中 linux文件系统遵循FHS(Filesystem Hierarchy Standard,文件系统目录标准),多数Linux版本采用这种文件组织形式.FHS采用了树行组织文件. FHS定义了两层规范,第一层是,/目录下面的各个目录应该要

[Z] linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO

原文链接:http://blog.csdn.net/colzer/article/details/8169075 IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file descriptor(fd,文件描述符).而对一个socket的读写也会有相应的描述符,称为socketfd(socket描述符).描述符就是一个数字,指向内核中一个结构体(文件路径,数据

python基础教程_学习笔记12:充电时刻——模块

充电时刻--模块 python的标准安装包括一组模块,称为标准库. 模块 >>> import math >>> math.sin(0) 0.0 模块是程序 任何python程序都可以作为模块导入. $ cat hello.py #!/usr/bin/python print "Hello,signjing!" $ ./hello.py Hello,signjing! 假设将python程序保存在/home/ggz2/magiccube/mysh/p