【问题1】
Write a C program that creates a new process to copy the files using the sample
MyCopy. This program should spawn a new process using fork system call. Then useexeclp to execute MyCopy program. The source and destination file names presented
as command-line arguments should be passed to execlp as system call arguments. The
main process waits for completion of copy operation using wait system call. Use
various system calls for time to calculate the execute time of this program.
【解答】
MyCopy.c
#include "header.h"
int main(int argc, char* argv[ ]){
if(argc!=3){ // parameter error
printf("Wrong Usage: MyCopy <source file name> <target file name>\n");
exit(-1);
}
FILE *src;
clock_t start,end; // the beginning and the end of the time
double elapsed; // period of time
struct timeval startTime, endTime;
struct timezone tz;
long run_time_in_microseconds;
start = clock(); //time count
gettimeofday(&startTime, &tz);
src = fopen(argv[1],"r"); //Open source file
//Check for file error
if(src==NULL){
printf("Error: Could not open file '%s'.\n",argv[1]);
exit(-1);
}
FILE *dest;
dest = fopen(argv[2],"w+"); //Open destination file
//Check for file error
if(dest==NULL){
printf("Error:Could not open file '%s'.\n",argv[2]);
fclose(src);
exit(-1);
}
char c;
//copy use fgetc fputc
while(!feof(src)){
c = fgetc(src);
if(!feof(src)) fputc(c,dest);
}
fclose(src);
fclose(dest);
end = clock();
gettimeofday(&endTime, &tz);
elapsed = ((double)(end-start))/CLOCKS_PER_SEC*1000; // time in millisecond
printf("MyCopy Time used:%f millisecond\n",elapsed);
run_time_in_microseconds = endTime.tv_usec - startTime.tv_usec;
printf("Time used: %ld microseconds.\n",run_time_in_microseconds);
exit(0);
}
ForkCopy.c
#include "header.h"
int main(int argc, char *argv[ ])
{
pid_t ForkPID;
ForkPID = fork(); // Using system call "fork" to create a new process
if (ForkPID>0){ // parent process
int status = 0;
wait(&status);
exit(0);
}else if (ForkPID==0){ // child process
execlp("./MyCopy", argv[0], argv[1], argv[2], NULL);
}else{ // fail to fork a child process
printf("Error: Failed to fork.\n");
exit(-1);
}
}
【问题2】
Make the mini shell (from the sample MyShell) a little more powerful by allowing
arguments to the commands. For example, it should be able to execute commands
such as more filename and ls -l ~/tmp etc.
【解答】
MoreShell.c
#include "header.h"
int main(int argc, char* argv[ ]){
if(argc!=1){
printf("Wrong Usage: MyShell\n");
exit(-1);
} //To start the mini-shell, you should call ./MoreShell
printf("PID:%d, MyShell (\"exit\" for end) >>", getpid()); //wait for the user to input some commands
char *buffer=NULL; size_t len=0;
while (1){
getline(&buffer, &len, stdin); //read the whole line
buffer[strlen(buffer)-1]='\0'; //replace the character '\n' by '\0' to indicate the end of the command buffer
if (!strcmp(buffer, "exit")) { free(buffer); break; } //if user's command is 'exit', the mini-shell is terminated.
char **argvs = (char **) malloc (sizeof(char *)); //ready to receive arguments of the command(seperated by whitespace)
int count=0; //number of arguments
//seperate the command using the way proposed by ppt
char *p=strtok(buffer, " ");
while (p!=NULL && strcmp(p,"|")!=0) {
argvs[count]=p;
count ++;
argvs = realloc(argvs, (count+1) * sizeof(char *));
p = strtok(NULL," ");
}
argvs[count]=NULL; //the last argument should be 'NULL'
pid_t ForkPID=fork(); //use system call 'fork' to create a new process for executing the given command
int status;
switch(ForkPID){
case -1: //failed to create the child process
printf("Error:Failed to fork.\n"); break;
case 0: //child process, first executes the given command then receives the status
if (execvp(argvs[0],argvs)==-1) printf("Error: running command: '%s'\n", argvs[0]);
exit(0);
break;
default: //parent process, waiting for child process to be finished
wait(&status);
}
printf("PID:%d, MyShell (\"exit\" for end) >>", getpid()); //waiting for the user to input next command
}
}
Modify the sample MyThread using two semaphores to control the program then
let thread 1 modify number before thread 2.
【解答】
MoreThread.c
#include "header.h"
int number;//protected external value
sem_t sem_id1, sem_id2;
//thread 1
void *thread_one_fun(void*argv){
sem_wait(&sem_id1); //get the acces to number
printf("Thread 1 is going to change the number.\n");
number++;
printf("Thread 1: number = %d \n",number);
sem_post(&sem_id2); //let thread two go after thread one has finished
pthread_exit(NULL);
}
//thread 2
void *thread_two_fun(void*argv){
sem_wait(&sem_id2); //if thread two executes first, it will be blocked for sem_id2 is 0 at the beginning.
printf("Thread 2 is going to change the number.\n");
number--;
printf("Thread 2: number = %d \n",number);
sem_post(&sem_id1); //after thread two has finished, post sem_id1
pthread_exit(NULL);
}
int main(int argc, char* argv[]){
number = 1;
printf("main function: number=1 at the beginning.\n");
sem_init(&sem_id1,0,1); //initialize sem_id1 to be 1
sem_init(&sem_id2,0,0); //initialize sem_id2 to be 0
pthread_t pt1,pt2;
int id[2]; id[0] = 1; id[1] = 2;
int rc;
rc=pthread_create(&pt1,NULL,thread_one_fun,&id[0]);
rc=pthread_create(&pt2,NULL,thread_two_fun,&id[1]);
void* status1;
rc = pthread_join (pt1, &status1);
if (rc) printf("ERROR: return code from pthread_join(pt1) is %d\n", rc);
void* status2;
rc = pthread_join (pt2, &status2);
if (rc) printf("ERROR: return code from pthread_join(pt2) is %d\n", rc);
sem_destroy(&sem_id1);
sem_destroy(&sem_id2);
printf("main function terminated.\n");
exit(0);
}