实验三 同步问题
16281141
1. 实验目的
 系统调用的进一步理解。
 进程上下文切换。
 同步的方法。
2 实验题目
1)通过fork的方式,产生4个进程P1,P2,P3,P4,每个进程打印输出自己的名字,例如P1输出“I am the process P1”。要求P1最先执行,P2、P3互斥执行,P4最后执行。通过多次测试验证实现是否正确。
在主函数中,使用5个信号量控制整个进程,其中2个信号量在1执行完之后被同时设置为1从而实现P1在P2和P3之前,1个信号量被用作P2和P3的互斥,另外2个信号量分别在P2和P3执行完之后被设置为1,从而实现P4在所有进程之后。实验结果与源代码如下。可以看出原来不同步的顺序为2143,经过同步的进程为1234或1324
操作系统实验三16281141
实现代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>

union semun
{
int val;
struct semid_ds *buf;
unsigned short *arry;
};

void set_value_of_sem(int sem_id, int sem_num, int val) {
union semun sem_union;
sem_union.val = val;
if (semctl(sem_id, sem_num, SETVAL, sem_union) == -1)
{
printf("%d %s\n", sem_id, “error - set value of semaphore”);
exit(1);
}
}

void set_values_of_sem(int sem_id, unsigned short *arry) {
union semun sem_union;
sem_union.arry = arry;
if (semctl(sem_id, sizeof(arry) - 1, SETALL, sem_union) == -1)
{
printf("%d %s\n", sem_id, “error - set values of semaphore”);
exit(1);
}
}

void delete_sem(int sem_id) {
union semun sem_union;
if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
{
printf("%s\n", “error - delete semaphore”);
exit(1);
}
}

void signal(int sem_id, int sem_num) {
struct sembuf sem_buff;
sem_buff.sem_num = sem_num;
sem_buff.sem_op = 1;
sem_buff.sem_flg = 0;

if (semop(sem_id, &sem_buff, 1) == -1)
{
	printf("%d %s\n", sem_id, "error - signal");
	exit(1);
}

}

void wait(int sem_id, int sem_num) {
struct sembuf sem_buff;
sem_buff.sem_num = sem_num;
sem_buff.sem_op = -1;
sem_buff.sem_flg = 0;

if (semop(sem_id, &sem_buff, 1) == -1)
{
	printf("%d %s\n", sem_id, "error - wait");
	exit(1);
}

}

int main(int argc, char const *argv[])
{

pid_t pid1, pid2, pid3;
int sem_id1, sem_id2, sem_id3;
sem_id1 = semget(1000, 2, 0666 | IPC_CREAT);
sem_id2 = semget(1001, 1, 0666 | IPC_CREAT);
sem_id3 = semget(1002, 2, 0666 | IPC_CREAT);

// printf("%d %d %d\n", sem_id1, sem_id2, sem_id3);

unsigned short init_arry[2] = {0, 0};
set_values_of_sem(sem_id1, init_arry);
set_value_of_sem(sem_id2, 0, 1);
set_values_of_sem(sem_id3, init_arry);

while ((pid1 = fork()) == -1);
if (pid1 > 0)
{
	while ((pid2 = fork()) == -1);
	if (pid2 > 0)
	{
		wait(sem_id1, 0);
		wait(sem_id2, 0);
		//printf("p2 pid: %d ppid: %d\n", getpid(), getppid() );
                    printf("I am the process P4\n");
		signal(sem_id2, 0);
		signal(sem_id3, 0);
		exit(0);
	}
	else
	{
		wait(sem_id3, 0);
		wait(sem_id3, 1);
		printf("p4 pid: %d ppid: %d\n", getpid(), getppid() );
                    printf("I am the process P1\n");
		delete_sem(sem_id1);
		delete_sem(sem_id2);
		delete_sem(sem_id3);
		exit(0);
	}
}
if (pid1 == 0)
{
	while ((pid3 = fork()) == -1);
	if (pid3 > 0)
	{
		//printf("p1 pid: %d ppid: %d\n", getpid(), getppid() );
                    printf("I am the process P3\n");
		unsigned short arry[2] = {1, 1};
		set_values_of_sem(sem_id1, arry);
		exit(0);
	}
	else
	{
		wait(sem_id1, 1);
		wait(sem_id2, 0);
		//printf("p3 pid: %d ppid: %d\n", getpid(), getppid() );
                    printf("I am the process P2\n");
		signal(sem_id2, 0);
		signal(sem_id3, 1);
		exit(0);
	}
}

return 0;

}
set_value_of_sem对单信号量赋值,set_values_of_sem可以同时对多个信号量赋值,signal和wait函数与信号量同步函数含义一致。
** 2)火车票余票数ticketCount 初始值为1000,有一个售票线程,一个退票线程,各循环执行多次。添加同步机制,使得结果始终正确。要求多次测试添加同步机制前后的实验效果。
操作系统实验三16281141
操作系统实验三16281141
售票、退票均运行100次
操作系统实验三16281141**售票线程的关键代码:
temp=ticketCount;
pthread_yield();
temp=temp-1;
pthread_yield();
ticketCount=temp;
退票线程的关键代码:
temp=ticketCount;
pthread_yield();
temp=temp+1;
pthread_yield();
ticketCount=temp;

全部代码:

#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <sched.h>
sem_t* mySem = NULL;
int tickets = 66666666;
voidsold(){
int i = 100;
while(i–){
// sem_wait(mySem);
printf(“Current tickes number is %d\n”,tickets);
int temp = tickets;
// sched_yield();
temp = temp - 1;
// sched_yield();
tickets = temp;
// sem_post(mySem);
}
}
void
returnT(){
int i = 100;
while(i–){
// sem_wait(mySem);
printf(“Current tickes number is %d\n”,tickets);
int temp = tickets;
// sched_yield();
temp = temp + 1;
// sched_yield();
tickets = temp;
// sem_post(mySem);
}
}
int main(){
pthread_t p1,p2;
mySem = sem_open(“Ticket”, O_CREAT, 0666, 1);
pthread_create(&p1,NULL,sold,NULL);
pthread_create(&p2,NULL,returnT,NULL);
pthread_join(p1,NULL);
pthread_join(p2,NULL);
sem_close(mySem);
sem_unlink(“Ticket”);
printf(“The finall value is %d.\n”,tickets);
return 0;
}

 3)一个生产者一个消费者线程同步。设置一个线程共享的缓冲区, char buf[10]。一个线程不断从键盘输入字符到buf,一个线程不断的把buf的内容输出到显示器。要求输出的和输入的字符和顺序完全一致。(在输出线程中,每次输出睡眠一秒钟,然后以不同的速度输入测试输出是否正确)。要求多次测试添加同步机制前后的实验效果。
操作系统实验三16281141
操作系统实验三16281141
算法实现与经典的生产者消费者模型一致,实验结果与源代码如下,test.txt与test_out.txt的内容完全一致
完整代码:”
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <time.h>

#define N 10

union semun
{
int val;
struct semid_ds *buf;
unsigned short *arry;
};

void set_init_value_of_sem(int sem_id, int init_value) {
union semun sem_union;
sem_union.val = init_value;
if (semctl(sem_id, 0, SETVAL, sem_union) == -1)
{
printf("%s\n", “error - inital semaphore”);
exit(1);
}
}

void delete_sem(int sem_id) {
union semun sem_union;
if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
{
printf("%s\n", “error - delete semaphore”);
exit(1);
}
}

void signal(int sem_id) {
struct sembuf sem_buff;
sem_buff.sem_num = 0;
sem_buff.sem_op = 1;
sem_buff.sem_flg = SEM_UNDO;

if (semop(sem_id, &sem_buff, 1) == -1)
{
	printf("%s\n", "error - signal");
	exit(1);
}

}

void wait(int sem_id) {
struct sembuf sem_buff;
sem_buff.sem_num = 0;
sem_buff.sem_op = -1;
sem_buff.sem_flg = SEM_UNDO;

if (semop(sem_id, &sem_buff, 1) == -1)
{
	printf("%s\n", "error - wait");
	exit(1);
}

}

int share_memory_id;
void *share_memory;
struct share_data
{
int in, out;
char buffer[N];
FILE *fp;
FILE *fp_out;
};
struct share_data *shared;
int empty, full, mutex;

int producer() {
wait(empty);
wait(mutex);
// printf("%p\n", shared->fp);
char ch = fgetc(shared->fp);
printf("%c", ch);
if (ch == EOF) {
signal(mutex);
// signal(full);
return 0;
}
shared->buffer[shared->in] = ch;
shared->in = (shared->in + 1) % N;
signal(mutex);
signal(full);

return 1;

}

int comsumer() {
wait(full);
wait(mutex);
printf(“out: %d “, shared->out);
char out_char = shared->buffer[shared->out];
if (out_char == EOF)
{
signal(mutex);
// signal(empty);
return 0;
}
shared->out = (shared->out + 1) % N;
fprintf(shared->fp_out, “%c”, out_char);
fflush(shared->fp_out);
printf(”%c”, out_char);

signal(mutex);
signal(empty);

return 1;	

}

int main(int argc, char const *argv[])
{

share_memory_id = shmget(12345, sizeof(struct share_data), 0666|IPC_CREAT);
share_memory = shmat(share_memory_id, 0, 0);
shared = (struct share_data *)share_memory;
shared->fp = fopen("test.txt", "r");
shared->fp_out = fopen("test_out.txt", "w");
if (shared->fp == NULL)
{
	printf("%s\n", "file open fail");
	return 0;
}
// printf("%p\n", shared->fp);
shared->in = 0; shared->out = 0;

empty = semget(3000, 1, 0666 | IPC_CREAT); 
full = semget(3001, 1, 0666 | IPC_CREAT);
mutex = semget(3002, 1, 0666 | IPC_CREAT);
set_init_value_of_sem(empty, N);
set_init_value_of_sem(full, 0);
set_init_value_of_sem(mutex, 1);

pid_t pid1, pid2;
while ((pid1 = fork()) == -1);
if (pid1 > 0)
{ 
	while ((pid2 = fork()) == -1);
	if (pid2 > 0)
	{
		while (producer()) {
			// usleep(100000);
		}
	}
	else {
		while (producer()) {
			// usleep(100000);
		}
	}
}
else
{
	while (comsumer()) 
		;
	printf("\n");
}

fclose(shared->fp_out);
fclose(shared->fp);

return 0;

}

 4)(2) 进程通信问题。阅读并运行共享内存、管道、消息队列三种机制的代码实验测试a)通过实验测试,验证共享内存的代码中,receiver能否正确读出sender发送的字符串?如果把其中互斥的代码删除,观察实验结果有何不同?如果在发送和接收进程中打印输出共享内存地址,他们是否相同,为什么?b)有名管道和无名管道通信系统调用是否已经实现了同步机制?通过实验验证,发送者和接收者如何同步的。比如,在什么情况下,发送者会阻塞,什么情况下,接收者会阻塞?c)消息通信系统调用是否已经实现了同步机制?通过实验验证,发送者和接收者如何同步的。比如,在什么情况下,发送者会阻塞,什么情况下,接收者会阻塞?
a)sender的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
int main(int argc, char *argv[])
{
key_t key;
int shm_id;
int sem_id;
int value = 0;

//1.Product the key     
    key = ftok(".", 0xFF);

//2. Creat semaphore for visit the shared memory     

sem_id = semget(key, 1, IPC_CREAT|0644);
if(-1 == sem_id)
{
perror(“semget”);
exit(EXIT_FAILURE);
}

//3. init the semaphore, sem=0     
      if(-1 == (semctl(sem_id, 0, SETVAL, value)))
{
    perror("semctl");
    exit(EXIT_FAILURE);
}

//4. Creat the shared memory(1K bytes)    
         shm_id = shmget(key, 1024, IPC_CREAT|0644);
if(-1 == shm_id)
{
    perror("shmget");
    exit(EXIT_FAILURE);
}

//5. attach the shm_id to this process     
 char *shm_ptr;
shm_ptr = shmat(shm_id, NULL, 0);
if(NULL == shm_ptr)
{
    perror("shmat");
    exit(EXIT_FAILURE);
}

    
     struct sembuf sem_b;
sem_b.sem_num = 0;      //first sem(index=0)     
sem_b.sem_flg = SEM_UNDO;
sem_b.sem_op = 1;           //Increase 1,make sem=1     

while(1)
{
if(0 == (value = semctl(sem_id, 0, GETVAL)))
{
printf("\nNow, snd message process running:\n");
printf("\tInput the snd message: “);
scanf(”%s", shm_ptr);

        if(-1 == semop(sem_id, &sem_b, 1))
        {
            perror("semop");
            exit(EXIT_FAILURE);
        }
    }

    //if enter "end", then end the process         
       if(0 == (strcmp(shm_ptr ,"end")))
    {
        printf("\nExit sender process now!\n");
        break;
    }
}
shmdt(shm_ptr);
return 0;

}
receiver的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
int main(int argc, char *argv[])
{
key_t key;
int shm_id;
int sem_id;
int value = 0;

//1.Product the key     

key = ftok(".", 0xFF);

//2. Creat semaphore for visit the shared memory     

sem_id = semget(key, 1, IPC_CREAT|0644);
if(-1 == sem_id)
{
perror(“semget”);
exit(EXIT_FAILURE);
}

//3. init the semaphore, sem=0     

if(-1 == (semctl(sem_id, 0, SETVAL, value)))
{
perror(“semctl”);
exit(EXIT_FAILURE);
}

//4. Creat the shared memory(1K bytes)     

shm_id = shmget(key, 1024, IPC_CREAT|0644);
if(-1 == shm_id)
{
perror(“shmget”);
exit(EXIT_FAILURE);
}

//5. attach the shm_id to this process     

char *shm_ptr;
shm_ptr = shmat(shm_id, NULL, 0);
if(NULL == shm_ptr)
{
perror(“shmat”);
exit(EXIT_FAILURE);
}

//6. Operation procedure     

struct sembuf sem_b;
sem_b.sem_num = 0; //first sem(index=0)
sem_b.sem_flg = SEM_UNDO;
sem_b.sem_op = -1; //Increase 1,make sem=1
while(1)
{
if(1 == (value = semctl(sem_id, 0, GETVAL)))
{
printf("\nNow, receive message process running:\n");
printf("\tThe message is : %s\n", shm_ptr);

        if(-1 == semop(sem_id, &sem_b, 1))
        {
            perror("semop");
            exit(EXIT_FAILURE);
        }
    }

    //if enter "end", then end the process         

if(0 == (strcmp(shm_ptr ,“end”)))
{
printf("\nExit the receiver process now!\n");
break;
}
}
shmdt(shm_ptr);

//7. delete the shared memory     

if(-1 == shmctl(shm_id, IPC_RMID, NULL))
{
perror(“shmctl”);
exit(EXIT_FAILURE);
}

//8. delete the semaphore     

if(-1 == semctl(sem_id, 0, IPC_RMID))
{
perror(“semctl”);
exit(EXIT_FAILURE);
}
return 0;
}
操作系统实验三16281141
操作系统实验三16281141
Receiver正确的输出了Sender写入共享内存中的数据。删除互斥代码后,sender开始运行后,scanf会自动阻塞,等待用户输入后再度唤醒。而receiver由于没有了信号量的限制,无限输出,难以继续运行。
b)
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main()
{
int filedes[2];
char buf[80];
pid_t pid_1;
if(-1 == pipe(filedes))
{
perror(“pipe”);
exit(EXIT_FAILURE);
}

pid_1 = fork();
if(pid_1 > 0){
    // father thread         
     sleep(2);
    printf("This is the father thread.\n");
    char s[] = "Hello, this is written by father.\n";
    write(filedes[1],s,sizeof(s));
    close(filedes[0]);
    close(filedes[1]);
} else if(pid_1 == 0)
{
    // child thread         
    printf("This is the child thread.\n");
    read(filedes[0],buf,sizeof(buf));
    printf("%s\n",buf);
    close(filedes[0]);
    close(filedes[1]);
}
return 0;

}

在父进程未向管道写入数据前,子进程在原地阻塞;当父进程执行完毕写入操作时,子进程才重新获得CPU得以将管道内容输出操作系统实验三16281141
c)client.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <signal.h>
#define BUF_SIZE 128
//Rebuild the strcut (must be)
struct msgbuf
{
long mtype;
char mtext[BUF_SIZE];
};
int main(int argc, char *argv[])
{
//1. creat a mseg queue
key_t key;
int msgId;
printf(“THe process(%s),pid=%d started~\n”, argv[0], getpid());
key = ftok(".", 0xFF);
msgId = msgget(key, IPC_CREAT|0644);
if(-1 == msgId)
{
perror(“msgget”);
exit(EXIT_FAILURE);
}
//2. creat a sub process, wait the server message
pid_t pid;
if(-1 == (pid = fork()))
{
perror(“vfork”);
exit(EXIT_FAILURE);
}
//In child process
if(0 == pid)
{
while(1)
{
alarm(0);
alarm(100); //if doesn’t receive messge in 100s, timeout & exit
struct msgbuf rcvBuf;
memset(&rcvBuf, ‘\0’, sizeof(struct msgbuf));
msgrcv(msgId, &rcvBuf, BUF_SIZE, 2, 0);
printf(“Server said: %s\n”, rcvBuf.mtext);
}
exit(EXIT_SUCCESS);
}
else //parent process
{
while(1)
{
usleep(100);
struct msgbuf sndBuf;
memset(&sndBuf, ‘\0’, sizeof(sndBuf));
char buf[BUF_SIZE] ;
memset(buf, ‘\0’, sizeof(buf));
printf("\nInput snd mesg: “);
scanf(”%s", buf);
strncpy(sndBuf.mtext, buf, strlen(buf)+1);
sndBuf.mtype = 1;
if(-1 == msgsnd(msgId, &sndBuf, strlen(buf)+1, 0))
{
perror(“msgsnd”);
exit(EXIT_FAILURE);
}
//if scanf “end~”, exit
if(!strcmp(“end~”, buf))
break;
}
printf(“THe process(%s),pid=%d exit~\n”, argv[0], getpid());
}
return 0;
}
sever.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <signal.h>
#define BUF_SIZE 128
//Rebuild the strcut (must be)
struct msgbuf
{
long mtype;
char mtext[BUF_SIZE];
};
int main(int argc, char argv[])
{
//1. creat a mseg queue
key_t key;
int msgId;
key = ftok(".", 0xFF);
msgId = msgget(key, IPC_CREAT|0644);
if(-1 == msgId)
{
perror(“msgget”);
exit(EXIT_FAILURE);
}
printf(“Process (%s) is started, pid=%d\n”, argv[0], getpid());
while(1)
{
alarm(0);
alarm(600); //if doesn’t receive messge in 600s, timeout & exit
struct msgbuf rcvBuf;
memset(&rcvBuf, ‘\0’, sizeof(struct msgbuf));
msgrcv(msgId, &rcvBuf, BUF_SIZE, 1, 0);
printf(“Receive msg: %s\n”, rcvBuf.mtext);
struct msgbuf sndBuf;
memset(&sndBuf, ‘\0’, sizeof(sndBuf));
strncpy((sndBuf.mtext), (rcvBuf.mtext),strlen(rcvBuf.mtext)+1);
sndBuf.mtype = 2;
if(-1 == msgsnd(msgId, &sndBuf, strlen(rcvBuf.mtext)+1, 0))
{
perror(“msgsnd”);
exit(EXIT_FAILURE);
}
//if scanf “end~”, exit
if(!strcmp(“end~”, rcvBuf.mtext))
break;
}
printf(“THe process(%s),pid=%d exit~\n”, argv[0], getpid());
return 0;
}
操作系统实验三16281141
操作系统实验三16281141
server端正常工作,client接收到server回复。
 5)阅读Pintos操作系统,找到并阅读进程上下文切换的代码,说明实现的保存和恢复的上下文内容以及进程切换的工作流程。
int main(){

/
获取命令行参数 */
char *argv = parse_options (argv);
/
初始化操作系统进程 /
thread_init ();

/
**空闲进程 idel thread,启动中断 /
thread_start ();

/
调用命令行指示的程序开始执行 */
run_actions (argv);

}

static void run_actions (char **argv)
{
struct action // 执行动作描述结构体 {
char *name;
int argc;
void (*function) (char **argv);
};

/* 可识别命令行参数列表 */
static const struct action actions[] =
{
{“run”, 2, run_task},

};

while (argv != NULL)
{

/
找到命令,传入参数,调用执行 */
a->function (argv);
argv += a->argc;
}
}

static void run_task (char **argv)
{
const char *task = argv[1]; // 获取运行需要的参数
printf (“Executing ‘%s’:\n”, task);
#ifdef USERPROG
process_wait (process_execute (task)); // 创建进程执行(针对用户程序) #else run_test (task);
#endif
printf (“Execution of ‘%s’ complete.\n”, task);
系统加载用户程序执行的基本方式是通过process_wait (process_execute (task));语句创建并执行任务。
操作系统实验三16281141

相关文章:

  • 2021-08-04
  • 2021-05-22
  • 2022-01-01
  • 2022-12-23
  • 2021-09-24
  • 2021-04-28
  • 2021-05-28
  • 2022-12-23
猜你喜欢
  • 2021-12-29
  • 2021-10-08
  • 2022-02-06
  • 2021-07-23
  • 2021-04-04
  • 2021-06-18
相关资源
相似解决方案