OS实验——测试磁盘读写速度与多进程并发(C语言,Linux)

前言

这几天换季了,身边的很多人包括自己都感冒了,大家要注意保暖防寒,适当运动,规律作息。这期的blog本来想分两期做的,结果这几天一直重感冒,拖到了现在,索性就来个二合一。
完整代码在文末

测试磁盘读写速度

对于这个实验,结合实验给出的样例,不难分析出需要的几个小知识点:malloc创建缓冲区,open、write、read这三个文件操作函数的使用以及gettimeofday()函数以及时间结构体的使用。

获取时间

时间结构体

struct timeval {
    time_t      tv_sec;     /* 秒*/
    suseconds_t tv_usec;    /* 微秒*/
};

以及 获取当前时间函数的声明

int gettimeofday(struct timeval *tv, struct timezone *tz);

二者的头文件

#include <sys/time.h>

相关使用可以参考如下例子

struct timeval startTime, endTime;
gettimeofday(&startTime, NULL);
//语句块;
gettimeofday(&endTime, NULL);
double timeElapse=(double)( endTime. tv_sec - startTime.tv_sec)*1000.0 + (double) ( endTime. tv_usec- startTime.tv_usec)/1000.0;

最终得到的timeElapse即为执行语句块所需的时间。当然,很容易可以知道,单位是毫秒。

创建缓冲区

头文件

#include<stdlib.h>

malloc创建缓冲区

char* buffer = (char*)malloc(sizeof(char) * 100 * MB);

这里强调一点,不能使用char buffer[] 来代替char* buffer,在linux下是不能通过gcc编译的,至于原因,个人觉得是前者属于将buffer视为一个数组,而后者才是一个字符串,或者是因为malloc创建的缓冲区以char*,不允许类型转换成char[]

文件操作函数

open
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int oflag);
int open(const char *path, int oflag, mode_t mode);

相关介绍如上,可以发现open函数的第三个参数可以有也可以没有,第三个参数表示文件的权限,mode用于指定文件创建时的访问权限。当传入mode参数后,文件的访问权限为mode&(~umask)。然后我们再看下linux下的输出
在这里插入图片描述
在这里插入图片描述
这就是不传mode和传mode的区别,不传的话open默认为550( 当不传入第三个参数时,即使用只含有两个参数的open,新创建的文件访问权限由底层算法指定。),我们指定了后输出一个644的权限,和mode一样,欸,前面不是还说会和umask取反做按位与嘛,怎么还是不变?因为我们的umask被我们设置为了001,所以最终输出的文件的权限也是0644。
在这里插入图片描述

write和read
#include <unistd.h>
size_t read(int fd, void *buf, size_t count);
size_t write(int fd, const void *buf, size_t count);
int close(int fd);

fd为文件描述符的int变量,由open函数返回得到,当fd < 0,时表示open失败。

代码思路

  1. 创建缓冲区
  2. 读写文件前后分别获取当前时间
  3. 用缓冲区比上获得的时间段即可

进程并发

两个比较重要的先导知识,fork() 和 wait() 函数

fork()函数:
创建子进程,同时会返回一个值,根据返回的值,我们可以判断创建子进程是否成功,以及当时处于父进程还是子进程。
wait()函数
我们一般使用wait(NULL),其作用是使当前最近的一个子进程结束,然后执行父进程,一般用于父进程中。

关于这两个函数以及并发的思路,我都是参照下列这位大大的blog,有需要的可以看看
链接

关于进程以及并发,首先要明确的1点是在该实验中,两个进程一个是compute进程,一个是IO进程,这两个进程一个主要占用的是CPU,另一个是IO这样的临界资源。对于一般的OS,我们默认cpu只有一个,因此CPU每次只能执行一个进程,而并发的好处在于其可以CPU执行一个进程,另外的资源(比如IO)执行另一个进程。
使用fork创建的父子进程会并发执行所有进程,当然由于cpu只有一个,且其中一个进程占cpu的时间会较长,所以相对来说,需要wait()去等待执行完子进程。

以下是源码
(测试读写速度)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/time.h>

#define MB 1048576

int main(int argc, char* argv[])
{
    char filename[] = "myfile05";
    // 100MB
    char* buffer = (char*)malloc(sizeof(char) * 100 * MB);
    buffer[MB] = '\0';
    size_t bufSize =  100 * MB * 5;

    struct timeval startWriteTime, endWriteTime;

    gettimeofday(&startWriteTime, NULL);

    int fd;
    fd = open(filename, O_RDWR | O_CREAT, 0777);
    if (fd < 0)
    {
        perror("Unable to  creat file");
        return -1;
    }

    size_t sizeWrited = write(fd, (void*)buffer, bufSize);
    printf("Write:%ldbytes to %s\n", sizeWrited, filename);
    gettimeofday(&endWriteTime, NULL);
    close(fd);
    double wirteTimeElapse = (double)(endWriteTime.tv_sec - startWriteTime.tv_sec) * 1000.0 + (double)(endWriteTime.tv_usec - startWriteTime.tv_usec) / 1000.0;
    double Vol_Write = sizeWrited * 1.0f * 1000/ wirteTimeElapse / MB;
    printf(" %lfMB/s\n", Vol_Write);

    fd = open(filename, O_RDWR);
    if (fd < 0)
    {
        perror("Unable to open file");
        return -1;
    }

    struct timeval readStime, readEtime;
    gettimeofday(&readStime, NULL);
    size_t sizeRead = read(fd, (void*)buffer, bufSize);
    gettimeofday(&readEtime, NULL);
    printf("Read:%ld bytes from %s, read content:%s\n", sizeWrited, filename, buffer);
    double ReadTime = (double)(readEtime.tv_sec - readStime.tv_sec) * 1000.0 + (double)(readEtime.tv_usec - readStime.tv_usec) / 1000.0;
    double Vol_read = sizeRead * 1.0f * 1000/ ReadTime / MB;
    printf("%lfMB/s\n", Vol_read);
    return 0;
}



(并发)

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <unistd.h>

#include "ComputeTask.h"
#include "IOTask.h"

typedef enum OP{

	COMPUTE_TASK=1,
	IO_TASK
}OP_t;

typedef struct task{
	struct task *next;
	OP_t taskType;
}task_t;

int main(int argc, char *argv[])
{
	double computeTaskTimeElapse=0.0;
	double IOTaskTimeElapse=0.0;
	double totalTimeElapse=0.0;

	struct timeval computeTaskStartTime, computeTaskEndTime,IOTaskStartTime, IOTaskEndTime;
	
	pid_t fpid;
	task_t computeTask, ioTask;
	task_t* curTask = &ioTask;

	computeTask.taskType = COMPUTE_TASK;
	ioTask.next=&computeTask;
	ioTask.taskType=IO_TASK;
	computeTask.next=NULL;

	int parentProcess = 1;
	int childProcessNum = 0;

	while(NULL!=curTask)
	{
		if(curTask->taskType==IO_TASK)
			gettimeofday(&IOTaskStartTime,NULL);
		else
			gettimeofday(&computeTaskStartTime,NULL);
		fpid=fork();
		if(0==fpid)
		{
			parentProcess=0;
			break;
		}
		else if(-1==fpid)
		{
			printf("Generate child Process error!\n");
			exit(0);
		}

		wait(NULL);
		
		if(COMPUTE_TASK==curTask->taskType)
			gettimeofday(&computeTaskEndTime,NULL);
		else
			gettimeofday(&IOTaskEndTime,NULL);
		printf("Generate child process with pid:%d\n",fpid);

		++childProcessNum;
		curTask=curTask->next;

	}

	if(parentProcess==0)
	{
		if(curTask->taskType==IO_TASK)
		{
			executeIOTask();
			printf("This is a IO task, pid:%d parent pid:%d\n",getpid(),getppid());//Print process ID and parent process ID
		}
		if(curTask->taskType==COMPUTE_TASK)
		{
			executeComputeTask();
			printf("This is a compute task, pid:%d parent pid:%d\n",getpid(),getppid());//Print process ID and parent process ID
		}
	}
	else
	{
		//Parent Process, we calculate the time for executing computing task and the time fo executing IO task
		computeTaskTimeElapse = (double)(computeTaskEndTime.tv_sec - computeTaskStartTime.tv_sec)*1000.0+(double)(computeTaskEndTime.tv_usec - computeTaskStartTime.tv_usec)/1000.0;
		IOTaskTimeElapse = (double)(IOTaskEndTime.tv_sec - IOTaskStartTime.tv_sec)*1000.0+(double)(IOTaskEndTime.tv_usec - IOTaskStartTime.tv_usec)/1000.0;
		totalTimeElapse = (double)(computeTaskEndTime.tv_sec-IOTaskStartTime.tv_sec)*1000.0+(double)(computeTaskEndTime.tv_usec-IOTaskStartTime.tv_usec)/1000.0;
		printf("Compute Task Time Consume:%fms, IO Task Time Consume: %fms, Total Time Consume:%fms \n", computeTaskTimeElapse,IOTaskTimeElapse,totalTimeElapse);
	}


}

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值