lab4-进程
【操作系统】Oranges学习笔记(五) 第六章 进程_memcpy0的博客-CSDN博客
问答
1、进程是什么?
《操作系统教程》上给出的定义是:进程是具有独立功能的程序在某个数据集合上的一次运行活动,是操作系统进行资源分配和保护的基本单位。
包括了程序计数器(Process Counter)、堆栈(Stack)、数据区域(Data Section)和其他资源、
而ORANGE’S(第172页)进行了具体的描述:从宏观来看,进程有自己的功能,且受控于进程调度模块;从微观上来看,它可以利用系统的资源,有自己的代码和数据,同时有自己的堆栈。
2、进程表是什么?
进程表就是进程控制块。它用来存储进程的标识信息(唯一标识该进程的信息)、现场信息(处理器运行时的现场信息)和控制信息(与管理、调度相关的信息)。进程创建时建立进程控制块,进程撤销时回收进程控制块,它与进程一一对应。
(来自PPT)PCB是OS用于记录和刻画进程状态及环境信息的数据结构。借助PCB,OS可以全面管理进程的物理实体,刻画进程的执行现状,控制进程的执行。
3、进程栈是什么?
(ORANGE’S第176页):进程运行时自身的堆栈
4、当寄存器的值已经被保存到进程表内, esp 应该指向何处来避免破坏进程表的值?
(ORANGE’S第176页):指向内核栈。
5、tty是什么?
终端,是一种字符型设备。多个终端分占显存的不同位置(但共用显示器和键盘)。
6、不同的tty为什么输出不同的画⾯在同⼀个显示器上?
不同的tty属领的console分别占有显存的不同位置,而通过端口0x3D4和0x3D5可以操纵显示器的寄存器的值从而指定从显存的某个位置开始显示,于是便可以在同一个显示器上输出不同的画面。
7、解释 tty任务执行的过程?
在tty任务完成初始化后,将通过一个循环轮询每一个tty。有两个阶段:
输入处理阶段:如果当前的控制台是轮询到的tty的控制台,他将会读取缓冲区并对得到的输入进行处理(比如处理内存中的键盘缓冲区的扫描码)。
输出处理阶段:如果缓冲区里有内容,则根据内容的情况写显存。
8、tty结构体中⼤概包括哪些内容?
struct s_console;
/* TTY */
typedef struct s_tty
{
u32 in_buf[TTY_IN_BYTES]; /* TTY 输入缓冲区 */
u32* p_inbuf_head; /* 指向缓冲区中下一个空闲位置 */
u32* p_inbuf_tail; /* 指向键盘任务应处理的键值 */
int inbuf_count; /* 缓冲区中已经填充了多少 */
struct s_console * p_console;
}TTY;
9、console结构体中⼤概包括哪些内容?
/* CONSOLE */
typedef struct s_console
{
unsigned int current_start_addr; /* 当前显示到了什么位置 */
unsigned int original_addr; /* 当前控制台对应显存位置 */
unsigned int v_mem_limit; /* 当前控制台占的显存大小 */
unsigned int cursor; /* 当前光标位置 */
}CONSOLE;
这里xl还在console里面加了一个8位的无符号成员color(应该是用来完成Lab3的颜色需求的),答的时候可以加上。
10、什么是时间⽚?
《操作系统教程》第5版第105页:
调度程序把CPU分配给就绪队列首进程/线程使用的规定的时间间隔。
来自xl的blog:时间片是分时操作系统分配给每个正在运行的进程微观上的一段 CPU 时间。
11、 结合实验代码解释什么是内核函数?什么是系统调⽤?
内核函数就是只能在内核态下调用的例程或子程序,比如kliba.asm中的disable_int,关中断显然不是用户进程能直接调用的(实际上这个文件里的所有函数都可以看作是内核函数)。
而ORANGE’S中对于系统调用则有如下实现:
先通过汇编代码(syscall.asm)完成参数的保存与发出中断,跳入内核态。内核态下调用中断处理例程(kernel.asm中)将控制权交给sys_call这一函数处理具体的系统调用型中断,该函数通过表驱动的方式再调用某一具体的系统调用函数(代码实现的位置因人而异)。
假设现在需要在用户程序中向终端输出一段字符串,就可以通过以下流程实现:
- 用户程序调用内核函数,将要输出的字符串传入内核函数参数;
- 内核通过适当的系统调用向终端输出该字符串;
- 结束后返回内核函数。
其中,用户程序调用的是内核函数,内核函数再通过系统调用将参数传递到内核,进行终端输出。具体的系统调用可使用 write 系统调用,例如:
// 内核函数
void print_to_terminal(char *str) {
int fd = 1; // 1表示标准输出
ssize_t count = write(fd, str, strlen(str));
// count表示实际写入的字节数
}
// 用户程序
int main() {
char *str = "Hello, world!";
print_to_terminal(str);
return 0;
}
在上述例子中,用户程序调用了内核函数 print_to_terminal
,内核函数中使用了系统调用 write
来将传入的字符串打印到终端上。
1、新增系统调用
proto.h
/* 以下是系统调用相关 */
/* 系统调用 - 系统级 */
/* proc.c */
PUBLIC int sys_get_ticks();
// PUBLIC int sys_write(char* buf, int len, PROCESS* p_proc);
PUBLIC void sys_print(char * s, int len);
PUBLIC void sys_sleep(int milli);
PUBLIC void sys_p(void * mutex);
PUBLIC void sys_v(void * mutex);
/* syscall.asm */
PUBLIC void sys_call(); /* int_handler */
/* 系统调用 - 用户级 */
PUBLIC int get_ticks();
PUBLIC void myprint(char* s, int len);
PUBLIC void mysleep(int milli);
PUBLIC void P(void * mutex);
PUBLIC void V(void * mutex);
// PUBLIC void write(char* buf, int len);
kernel.asm
341-356
sys_call:
call save
;push dword [p_proc_ready] ;以防发生进程切换,这里在开中断前压入
sti
push ecx
push ebx
call [sys_call_table + eax * 4]
pop ebx
pop ecx
mov [esi + EAXREG - P_STACKBASE], eax
cli
ret
syscall.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; syscall.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%include "sconst.inc"
;必增内容!!!!!!!!!
INT_VECTOR_SYS_CALL equ 0x90
_NR_get_ticks equ 0
_NR_Print equ 1
_NR_Sleep equ 2
_NR_P equ 3
_NR_V equ 4
; 导出符号
global get_ticks
global myprint
global mysleep
global P
global V
bits 32
[section .text]
; ====================================================================
; get_ticks
; ====================================================================
get_ticks:
mov eax, _NR_get_ticks
int INT_VECTOR_SYS_CALL
ret
myprint:
mov eax,_NR_Print
push ebx
push ecx
mov ebx,[esp+12] ;字符串
mov ecx,[esp+16] ;颜色
int INT_VECTOR_SYS_CALL
pop ecx
pop ebx
ret
mysleep:
mov eax,_NR_Sleep
push ebx
mov ebx,[esp+8]
int INT_VECTOR_SYS_CALL
pop ebx
ret
P:
push ebx ; 保存Ebx现场
mov eax, _NR_P
mov ebx, [esp+8] ; 读取信号量地址
int INT_VECTOR_SYS_CALL ; 执行中断,通过中断服务例程跳转到内核系统中执行相应操作
pop ebx; 恢复Ebx现场
ret ; 返回结果
V:
push ebx
mov eax, _NR_V
mov ebx, [esp+8]
int INT_VECTOR_SYS_CALL
pop ebx
ret
; ====================================================================================
; void write(char* buf, int len);
; ====================================================================================
; write:
; mov eax, _NR_write
; mov ebx, [esp + 4]
; mov ecx, [esp + 8]
; int INT_VECTOR_SYS_CALL
; ret
clock.c
19-63
/*======================================================================*
clock_handler
*======================================================================*/
// 这个是用于切换进程的
PUBLIC void clock_handler(int irq)
{
// 时钟中断次数递增
ticks++;
// 当前进程的剩余时间片减1
p_proc_ready->ticks--;
// 我的修改
// 从第一个进程循环到最后一个进程
for(PROCESS* p = proc_table; p < proc_table + NR_PROCS + NR_TASKS; p++){
// 对需要唤醒的进程进行计时
if(p->wakeup > 0){
p->wakeup--;
}
}
// 如果内核重入标志不为0,则表示当前处理器已在处理中断程序
// 为了避免重入造成的问题,需要立即返回
if (k_reenter != 0) {
return;
}
// 如果当前进程还有剩余时间片,则不进行进程调度
if (p_proc_ready->ticks > 0) {
return;
}
// disp_str("change");
// 进程时间片用完,进行进程调度
schedule();
}
/*======================================================================*
milli_delay
*======================================================================*/
PUBLIC void milli_delay(int milli_sec)
{
int t = get_ticks();
// 等待指定的时间
while(((get_ticks() - t) * 1000 / HZ) < milli_sec) {}
}
proc.c
18
/*======================================================================*
schedule
为没有睡眠和阻塞的进程分配时间片
*======================================================================*/
PUBLIC void schedule() {
PROCESS *p;
int greatest_ticks = 0;
while (!greatest_ticks) {
for (p = proc_table; p < proc_table + NR_TASKS + NR_PROCS; p++) {
if (p->wakeup > 0 || p->block == 1) continue;
// 正在睡眠/阻塞的进程不会被执行(也就是不会被分配时间片)
if (p->ticks > greatest_ticks) {
//分配时间片
greatest_ticks = p->ticks;
p_proc_ready = p;
}
}
// 如果都是 0,那么需要重设 ticks
if (!greatest_ticks) {
for (p = proc_table; p < proc_table + NR_TASKS + NR_PROCS; p++) {
if (p->ticks > 0) continue; // >0 还进入这里只能说明它被阻塞了
p->ticks = p->priority;
}
}
}
}
/*======================================================================*
sys_get_ticks
*======================================================================*/
PUBLIC int sys_get_ticks()
{
return ticks;
}
PUBLIC void sys_print(char * s, int len){
CONSOLE *p_con = console_table;
for (int i = 0; i < len; i++) {
out_char(p_con, s[i]);
}
}
// 如果我没有理解错的话,p_proc_ready 是已经在处理机器上运行的进程
PUBLIC void sys_sleep(int milli){
int ticks = milli / 1000 * HZ * 10;
//wakeup > 0会被认为正在sleep
p_proc_ready->wakeup = ticks;
schedule();// 切换到下一个进程
}
2、读者写者问题
proc.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
proc.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
typedef struct s_stackframe { /* proc_ptr points here ↑ Low */
u32 gs; /* ┓ │ */
u32 fs; /* ┃ │ */
u32 es; /* ┃ │ */
u32 ds; /* ┃ │ */
u32 edi; /* ┃ │ */
u32 esi; /* ┣ pushed by save() │ */
u32 ebp; /* ┃ │ */
u32 kernel_esp; /* <- 'popad' will ignore it │ */
u32 ebx; /* ┃ ↑栈从高地址往低地址增长*/
u32 edx; /* ┃ │ */
u32 ecx; /* ┃ │ */
u32 eax; /* ┛ │ */
u32 retaddr; /* return address for assembly code save() │ */
u32 eip; /* ┓ │ */
u32 cs; /* ┃ │ */
u32 eflags; /* ┣ these are pushed by CPU during interrupt │ */
u32 esp; /* ┃ │ */
u32 ss; /* ┛ ┷High */
}STACK_FRAME;
// 进程的状态统统在s_proc这个结构体里面
typedef enum{
WAITING, WORKING, RELAXING
}STATUS;
//进程的结构体
typedef struct s_proc {
STACK_FRAME regs; /* process registers saved in stack frame *//* 进程寄存器,保存在栈帧中 */
u16 ldt_sel; /* gdt selector giving ldt base and limit */ // LDT 选择子,用于获取 LDT 的基地址和限制 /
DESCRIPTOR ldts[LDT_SIZE]; /* local descriptors for code and data */ // 保存代码段和数据段的局部描述符符表 /
int ticks; /* remained ticks */ // 剩余的时钟中断数量 /
int priority; // 进程的优先级 /
int wakeup;
int block;
int done;
STATUS status;
u32 pid; /* process id passed in from MM */
char p_name[16]; /* name of the process */
int nr_tty; // 进程所在的终端 */
}PROCESS;
// 任务结构体
typedef struct s_task {
task_f initial_eip;/* 任务的起始地址 */
int stacksize;// / 任务的堆栈大小 /
char name[32];//任务的名字 */
}TASK;
/* Number of tasks & procs */
/* 任务和进程的数量 */
#define NR_TASKS 1
#define NR_PROCS 6
// 信号量结构体
typedef struct semaphore
{
/* data */
int value;
PROCESS* queue[NR_PROCS];
} Semaphore;
/* stacks of tasks */
/* 任务的堆栈大小 */
#define STACK_SIZE_TTY 0x8000
#define STACK_SIZE_TESTA 0x8000
#define STACK_SIZE_TESTB 0x8000
#define STACK_SIZE_TESTC 0x8000
#define STACK_SIZE_TESTD 0x8000
#define STACK_SIZE_TESTE 0x8000
#define STACK_SIZE_TESTF 0x8000
/* 所有任务的堆栈大小总和 */
#define STACK_SIZE_TOTAL (STACK_SIZE_TTY + \
STACK_SIZE_TESTA + \
STACK_SIZE_TESTB + \
STACK_SIZE_TESTC + \
STACK_SIZE_TESTD + \
STACK_SIZE_TESTE + \
STACK_SIZE_TESTF )
proto.h
/* 以下是系统调用相关 */
/* 系统调用 - 系统级 */
/* proc.c */
PUBLIC int sys_get_ticks();
// PUBLIC int sys_write(char* buf, int len, PROCESS* p_proc);
PUBLIC void sys_print(char * s, int len);
PUBLIC void sys_sleep(int milli);
PUBLIC void sys_p(void * mutex);
PUBLIC void sys_v(void * mutex);
/* syscall.asm */
PUBLIC void sys_call(); /* int_handler */
/* 系统调用 - 用户级 */
PUBLIC int get_ticks();
PUBLIC void myprint(char* s, int len);
PUBLIC void mysleep(int milli);
PUBLIC void P(void * mutex);
PUBLIC void V(void * mutex);
// PUBLIC void write(char* buf, int len);
global.c
PUBLIC TASK user_proc_table[NR_PROCS] = {
{reporter_A, STACK_SIZE_TESTA, "reporter_A"},
{reader_B, STACK_SIZE_TESTB, "reader_B"},
{reader_C, STACK_SIZE_TESTC, "reader_C"},
{reader_D, STACK_SIZE_TESTD, "reader_D"},
{writer_E, STACK_SIZE_TESTE, "writer_E"},
{writer_F, STACK_SIZE_TESTF, "writer_F"}};
main.c
18-19
char sign[3] = {'X', 'O', 'Z'};
char color[3] = {'\01','\02', '\03'};
23-38
// 读者优先的解决饥饿的办法就是并发量,并发量越高越不会发生饥饿,现在其实就不需要改
// 文件的读写还是需要sleep
PRIVATE void init_tasks()
{
// 表驱动,对应进程0, 1, 2, 3, 4, 5, 6
int prior[7] = {1, 1, 1, 1, 1, 1, 1};
for (int i = 0; i < 7; ++i) {
proc_table[i].ticks = prior[i];
proc_table[i].priority = prior[i];
}
// initialization
k_reenter = 0;
ticks = 0;
p_proc_ready = proc_table;
}
112-120
reader_mutex.value = 1;
reader_count = 0;
writer.value = 1;
reader_count_max.value = 3;
writer_count = 0;
writer_mutex.value = 1;
writer_premission.value = 1;
read_premission.value = 1;
S.value = 1;
131-311
PUBLIC void reporter_A(){
// time slice = 1000
mysleep(TIMESLICE);
// int time = 0;
while(1){
for(int i = 1; i <= 20; i++){
printf("%c%c%c ", '\06',i / 10 + '0', i % 10 + '0');
for(int j = NR_TASKS + 1; j < NR_PROCS + NR_TASKS; j++){
int proc_status = (proc_table + j)->status;
printf("%c%c ", color[proc_status], sign[proc_status]);
}
printf("\n");
mysleep(TIMESLICE);
}
while(1);
}
}
PUBLIC void reader_B(){
while(1){
// reader_rfirst(2);
// reader_fair(2);
read_wfirst(2);
p_proc_ready->status = RELAXING;
// mysleep(2000);
p_proc_ready->status = WAITING;
}
}
PUBLIC void reader_C(){
while(1){
// mysleep(3000);
// reader_rfirst(2);
// reader_fair(2);
read_wfirst(2);
p_proc_ready->status = RELAXING;
// mysleep(2000);
p_proc_ready->status = WAITING;
}
}
PUBLIC void reader_D(){
while(1){
// mysleep(3000);
// reader_rfirst(3);
// reader_fair(3);
read_wfirst(3);
p_proc_ready->status = RELAXING;
// mysleep(2000);
p_proc_ready->status = WAITING;
}
}
PUBLIC void writer_E(){
while(1){
// writer_rfirst(3);
// writer_fair(3);
writer_wfirst(3);
p_proc_ready->status = RELAXING;
// mysleep(2000);
p_proc_ready->status = WAITING;
}
}
PUBLIC void writer_F(){
while(1){
// mysleep(2000);
// writer_rfirst(5);
// writer_fair(3);
writer_wfirst(5);
p_proc_ready->status = RELAXING;
// mysleep(2000);
p_proc_ready->status = WAITING;
}
}
void read_proc(int time_slice){
p_proc_ready->status = WORKING;
// disp_str("here");
mysleep(time_slice);
// milli_delay(time_slice);
}
void write_proc(int time_slice){
p_proc_ready->status = WORKING;
mysleep(time_slice);
// milli_delay(time_slice);
}
void reader_rfirst(int slices){
P(&reader_mutex);
if(reader_count == 0){
P(&writer);
}
reader_count++;
V(&reader_mutex);
P(&reader_count_max);
read_proc(TIMESLICE * slices);
V(&reader_count_max);
P(&reader_mutex);
reader_count--;
if(reader_count == 0){
V(&writer);
}
V(&reader_mutex);
}
void writer_rfirst(int slices){
P(&writer);
write_proc(TIMESLICE * slices);
V(&writer);
}
void reader_fair(int slices){
P(&S);
P(&reader_count_max);
P(&reader_mutex);
if(reader_count == 0){
P(&writer);
}
reader_count++;
V(&reader_mutex);
V(&S);
read_proc(TIMESLICE * slices);
P(&reader_mutex);
reader_count--;
if(reader_count == 0){
V(&writer);
}
V(&reader_mutex);
V(&reader_count_max);
}
void writer_fair(int slices){
P(&S);
P(&writer);
write_proc(TIMESLICE * slices);
V(&writer);
V(&S);
}
void read_wfirst(int slices){
P(&reader_count_max);
P(&read_premission);
P(&reader_mutex);
if(reader_count == 0){
P(&writer_premission);
}
reader_count++;
V(&reader_mutex);
V(&read_premission);
read_proc(slices * TIMESLICE);
P(&reader_mutex);
if (--reader_count == 0)
V(&writer_premission); // 没有读者时可以开始写
V(&reader_mutex);
V(&reader_count_max);
}
void writer_wfirst(int slices){
P(&writer_mutex);
if(writer_count == 0){
P(&read_premission);
}
writer_count++;
V(&writer_mutex);
P(&writer_premission);
write_proc(slices * TIMESLICE);
V(&writer_premission);
P(&writer_mutex);
writer_count--;
if(writer_count == 0){
V(&read_premission);
}
V(&writer_mutex);
}
实验任务3:生产者消费者问题(2分)
main.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
main.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
char sign[3] = {'X', 'O', 'Z'};
char color[3] = {'\01','\02', '\03'};
// 假设p1生产橘子, p2生产apple
PRIVATE void init_tasks()
{
// 表驱动,对应进程0, 1, 2, 3, 4, 5, 6
int prior[7] = {1, 1, 1, 1, 1, 1, 1};
for (int i = 0; i < 7; ++i) {
proc_table[i].ticks = prior[i];
proc_table[i].priority = prior[i];
}
// initialization
k_reenter = 0;
ticks = 0;
p_proc_ready = proc_table;
}
PUBLIC int clean_screen(){
disp_pos = 0;
for (int i = 0 ; i < SCREEN_SIZE; ++i){
disp_str(" ");
}
disp_pos = 0;
}
/*======================================================================*
kernel_main
*======================================================================*/
PUBLIC int kernel_main()
{
disp_str("-----\"kernel_main\" begins-----\n");
clean_screen();
TASK* p_task = task_table;
PROCESS* p_proc = proc_table;
char* p_task_stack = task_stack + STACK_SIZE_TOTAL;
u16 selector_ldt = SELECTOR_LDT_FIRST;
u8 privilege;
u8 rpl;
int eflags;
for (int i = 0; i < NR_TASKS+NR_PROCS; i++) {
if (i < NR_TASKS) { /* 任务 */
p_task = task_table + i;
privilege = PRIVILEGE_TASK;
rpl = RPL_TASK;
eflags = 0x1202; /* IF=1, IOPL=1, bit 2 is always 1 */
}
else { /* 用户进程 */
p_task = user_proc_table + (i - NR_TASKS);
privilege = PRIVILEGE_USER;
rpl = RPL_USER;
eflags = 0x202; /* IF=1, bit 2 is always 1 */
}
strcpy(p_proc->p_name, p_task->name); // name of the process
p_proc->pid = i; // pid
p_proc->wakeup = 0; // 初始化结构体新增成员
p_proc->block = 0;
p_proc->status = RELAXING; // pid
p_proc->total = 0;
p_proc->ldt_sel = selector_ldt;
memcpy(&p_proc->ldts[0], &gdt[SELECTOR_KERNEL_CS >> 3],
sizeof(DESCRIPTOR));
p_proc->ldts[0].attr1 = DA_C | privilege << 5;
memcpy(&p_proc->ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3],
sizeof(DESCRIPTOR));
p_proc->ldts[1].attr1 = DA_DRW | privilege << 5;
p_proc->regs.cs = (0 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl; // 初始化寄存器
p_proc->regs.ds = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
p_proc->regs.es = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
p_proc->regs.fs = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
p_proc->regs.ss = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
p_proc->regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | rpl;
p_proc->regs.eip = (u32)p_task->initial_eip;
p_proc->regs.esp = (u32)p_task_stack;
p_proc->regs.eflags = eflags;
p_proc->nr_tty = 0;
p_task_stack -= p_task->stacksize;
p_proc++;
p_task++;
selector_ldt += 1 << 3;
}
/**
* empty_mutex
*/
empty_mutex.value = 5;
full_mutex.value = 0;
apple_mutex.value = 0;
orange_mutex.value = 0;
consume_apple_mutex.value = 1;
init_tasks(); // 扳机
init_clock(); // 在这里实现了时钟的中断
// init_keyboard(); // 在这里实现了键盘的中断
restart();
while(1){}
}
PUBLIC void reporter_A(){
mysleep(TIMESLICE);
// int time = 0;
while(1){
for(int i = 1; i <= 20; i++){
printf("%c%c%c ", '\06',i / 10 + '0', i % 10 + '0');
for(int j = NR_TASKS + 1; j < NR_PROCS + NR_TASKS; j++){
int num = (proc_table + j)->total;
// if(j == NR_TASKS + 1){
// num = num - (proc_table + j + 2)->total;
// }
// else if(j == NR_TASKS + 2){
// num = num - (proc_table + j + 2)->total - (proc_table + j + 3)->total;
// }
printf("%c%c%c ", '\06',num / 10 + '0', num % 10 + '0');
}
printf("\n");
mysleep(TIMESLICE);
}
while(1);
}
}
PUBLIC void p_orange(){
while(1){
P(&empty_mutex);
produce_porc();
mysleep(1000);
V(&orange_mutex);
// V(&full_mutex);
}
}
PUBLIC void p_apple(){
while(1){
P(&empty_mutex);
produce_porc();
mysleep(1000);
V(&apple_mutex);
// V(&full_mutex);
}
}
PUBLIC void c_orange(){
while(1){
// P(&full_mutex);
P(&orange_mutex);
consume_proc();
mysleep(1000);
V(&empty_mutex);
}
}
PUBLIC void c_apple_1(){
while(1){
// P(&consume_apple_mutex);
// P(&full_mutex);
P(&apple_mutex);
consume_proc();
mysleep(1000);
V(&empty_mutex);
// V(&consume_apple_mutex);
}
}
PUBLIC void c_apple_2(){
while(1){
// P(&consume_apple_mutex);
// P(&full_mutex);
P(&apple_mutex);
consume_proc();
mysleep(1000);
V(&empty_mutex);
// V(&consume_apple_mutex);
}
}
PUBLIC void produce_porc(){
p_proc_ready->total++;
// mysleep(1000);
}
PUBLIC void consume_proc(){
p_proc_ready->total++;
// mysleep(1000);
}