西电操作系统:进程程序复习

Proccess And Thread

1、fork()和exec()的区别

fork()创建新的进程,父子进程拥有相同的内存映像;

对于父进程来说fork获得的pid是创建的子进程的pid,对于子进程来说fork获得的pid是0;

#include <unistd.h>
#include <stdio.h>
int main(){
	pid_t pid;
    pid = fork();
    if( pid == 0 ){
        while(1){
            sleep(1);
            printf("haha\n");	//子进程会一直打印haha
        }
    }
    if( pid > 0 ){
        while(1){
            sleep(1);
            printf("hehe\n");	//父进程会一直打印hehe
        }
    }
    return 0;
}

exec()是以新的程序去代替原来的程序,但进程的PID保持不变。因此,可以这样认为,exec系统调用并没有创建新的进程,只是替换了原来进程上下文的内容。原进程的代码段,数据段,堆栈段被新的进程所代替。fork()后产生父子进程,拥有相同内存印象。子进程执行exec,修改内存映像,运行新的程序.

#include <unistd.h>
#include <stdio.h>
int main(){
    pid_t pid;
    pid = fork();
    if(pid==0){
        execl("/bin/ls", "ls", "-l", 0);	//子进程切换,调用执行新的程序,不再会打印出haha
        while(1){
            sleep(1);
            printf("haha\n");
        }
    }
    if(pid>0){
        while(1){
            sleep(1);
            printf("hehe\n");			//父进程继续打印hehe
        }
    }
}

2、pthread

#include <stdio.h>
#include <pthread.h>
int a;
void * th(void *p){
    int i = 0;
    while(1){
        a = 1; i++;
        sleep(1);
        if(i<5)
            printf("haha\n");
    }
}
int main()
{
	int i = 0;
    a = 0;
    pthread_t myth;
    pthread_create(&myth, NULL, th, NULL);
    while(1)
    {
        i++; sleep(1);
        if(i <= 5)
            printf("a=%d hehe\n", a);
    }
    return 0;
}

pthread_create(&myth, NULL, th, NULL)生成了线程:表示要执行的程序标段。

3、进程和线程的区别

同一个进程的线程之间是共享:程序段,数据段,代码段的

但是:PSW,PC,堆栈,寄存器是不共享的。

4、Mutual Exclusion with Busy waiting

(1) 锁变量

连续测试一个变量直到出现某个值为止,称为忙等待

用于忙等待的锁称为自旋锁。

while(TRUE){
    while(turn!=0);	/*忙等待*/
    critical_region();
    turn = 1;
    noncritical_region();
}

while(TRUE){
	while(turn!=1);/*忙等待*/
    critical_region();
    trun = 0;
    noncritical_region(;)
}

需要严格地轮换执行

(2) Peterson解法

用了两个变量避免轮转:

#define FALSE 0
#define TRUE 1
#define N 2

int turn;
int interested[N];

void enter_region(int process)
{
    int other;
    other = 1 - process;
    interested[process] = TRUE;
    turn = process;
    while(turn == process && interested[other] == TRUE);	//空语句,无法进入关键区
}

void leave_region(int process){
    interested[process] = FALSE;	//表示离开临界区
}

(3) TSL指令

TSL RX, LOCK:测试并加锁;将锁字lock读到寄存器RX中,然后将锁值设为1;

读字和写操作保证是不可分的。即该指令结束前不允许其他处理器访问该内存字。执行TSL指令需要锁住总线

注意,在TSL指令中,LOCK为0是表示未上锁,为1时表示上锁

enter_region:
	TSL REGISTER, LOCK		|复制锁值到寄存器,并将锁设置为1
	CMP REGISTER, #0		|锁是0吗?是0表示没有上锁,可以进入关键区
	JNE enter_region		|锁值非零,已经上锁,不能进入关键区
	RET						|返回调用者,进入临界区

leave_region:
	MOVE LOCK, #0			|将锁值设置为0,解锁
	RET 					|离开关键区

另外TSL指令可以被XCHG指令代替:

enter_region:
	MOVE REGISTER, #1
	XCHG REGISTER, LOCK
	CMP REGISTER, #0
	JNE enter_region
	RET
leave_region:
	MOVE LOCK, #0
	RET

5、Sleeping and Wakeup

具有严重的竞争条件的生产者与消费者问题。

丢失唤醒信号!!!会导致整个的睡眠

6、信号量

#define N 100
typedef int semaphore;
semaphore mutex = 1;
semaphore empty = N;
semaphore full = 0;

void produce()
{
	int item;
    while(TRUE){
        item = produce_item();
        down(&empty);
        down(&mutex);
        isert_item(item);
        up(&mutex);
        up(&full); 
    }
}

void consume()
{
    int item;
    while(TRUE){
        down(&full);
        down(&mutex);
        item = remove_item();
        up(&mutex);
        up(&empty);
        consume_item(item);
    }
}

7、互斥量

信号量的简化版本。仅适用于管理共享资源或一小段代码。在实现用户空间线程包时非常有用。值只有0和1。这是不同于semaphore的显著区别。

mutex_lock:
	TSL REGISTER, LOCK
	CMP RESISTER, #0
	JZE ok					|锁是0吗?是零的话,那么跳转
	CALL thread_yield		 |与忙等待不同之处,让出了CPU的使用权
	JMP mutex_lock
ok: RET
mutex_unlock:
	MOVE mutex, #0
	RET

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LX7C5J9V-1625280764315)(C:/Users/%E5%AD%99%E8%95%B4%E7%90%A6/AppData/Roaming/Typora/typora-user-images/image-20210621184404415.png)]

互斥量和conditional variable联合使用,解决生产者和消费者问题:

#include<stdio.h>
#include<pthread.h>
#define MAX 1000000000	/*需要生产的数量*/
pthread_mutex_t the_mutex;
pthread_cond_t condc, condp;
int buffer = 0;

void *producer(void *ptr)
{
    int i;
    for(i = 1; i<= MAX;i++){
        pthread_mutex_lock(&the_mutex);	//给mutex上锁
        while(buffer! = 0)pthread_cond_wait(&condp, &the_mutex);
        buffer = i;
        pthread_cond_signal(&condc);	//唤醒消费者
        pthread_mutex_unlock(&the_mutex);	//释放缓冲区
    }
    pthread_exit(0);
}

void consumer(void *ptr)
{
    int i;
    for(i = 0; i<=MAX; i++){
        pthread_mutex_lock(&the_mutex);
        while(buffer == 0)pthread_cond_wait(&condc, &the_mutex);
        buffer = 0;
        pthread_cond_signal(&condp);	//唤醒生产者
        pthread_mutex_unlock(&the_mutex);
    }
    pthread_exit(0);
}

int main()
{
    pthread_t pro, con;
    pthread_mutex_init (&the_mutex, 0);
    pthread_cond_init(&condc, 0);
    pthread_cond_init(&condp, 0);
    pthread_create(&con, 0, consumer, 0);
    pthread_create(&pro, 0, producer, 0);
    pthread_join(pro, 0);
    pthread_join(con, 0);
    pthread_cond_destory(&condc);
    pthread_cond_destory(&condp);
    pthread_mutex_destory(&the_mutex);
}

8、经典IPC问题

(1)哲学家就餐问题

#define N			5
#define LEFT		(i+N-1)%N
#define RIGHT		(i+1)%N
#define THINKING	0
#define HUNGRY		1
#define EATING		2

typedef int semaphore;
int state[N];
semaphore mutex = 1;	//对状态表的互斥访问
semaphore s[N];		//到底有无获得叉子

void philosopher(int i)
{
    while(TRUE){
	}
}

void take_forks(int i)
{
    down(&mutex);		//保护状态表
    state[i] = HUNGRY;
    test(i);		//询问一下邻居能不能吃
    up(&mutex);		
    down(&s[i]);	//拿不到叉子会阻塞
}

void put_forks(i)
{
    down(&mutex);
    state[i] = THINKING;
    test(LEFT);
    test(RIGHT);
    up(&mutex);
}

void test(i)
{
    if(state[i] == HUNGERY && state[LEFT] != EATING && state[RIGHT] != EATING){
        state[i] = EATING;
        up(&s[i]);
    }
}

(2)读者写者问题

typedef int semaphore;
semaphore mutex = 1;					//互斥:rc
semaphore db = 1;						//互斥:数据库访问
int rc = 0;								//读者数

void reader()
{
    while(TRUE){
        down(&mutex);
        rc = rc+1;
        if(rc==1)down(&db);
        up(&mutex);
        
        read_data_base;
        
        down(&mutex);
        rc = rc -1;
        if(rc == 0) up(&db);
        up(&mutex);
        use_data_read;
    }
}

void writer()
{
    while(TRUE){
        think_up_data();
        down(&db);
        write_data_base();
        up(&db);
    }
}

9、消息传递解决生产者和消费者问题

#define N 100
void producer(void)
{
	int item;
    message m;
    
    while(TRUE){
        item = produce_item();
        receive(consumer, &m);
        build_message(&m, item);
        send(consumer, &m);
    }
}

void consumer(void)
{
    int item, i;
    message m;
    
    for(int i = 0;i<N;i++){
        send(producer, &m);
    }
    while(TRUE){
        
    }
}
#define N 100
void producer(void)
{
	int item;
    message m;
    
    while(TRUE){
        item = produce_item();
        receive(consumer, &m);
        build_message(&m, item);
        send(consumer, &m);
    }
}

void consumer(void)
{
    int item, i;
    message m;
    
    for(int i = 0;i<N;i++){
        send(producer, &m);
    }
    while(TRUE){
        
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Blanche117

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值