1 需求说明
1.1 基本需求
目标:
本次实验的目标是在Linux环境下实现一个多线程对临界资源的互斥操作,利用信号量实现对临界资源的保护,支持Linux下文件输入输出,提高对Linux环境下多进程、多线程、信号量机制和文件操作等知识的理解。
问题描述:
设有进程A、B、C,分别调用过程get、copy、put对缓冲区S和T进行操作。其中get负责从文件F_in中把数据块读入并输出缓冲区S,copy负责从S中提取数据块并复制到缓冲区T中,put负责从缓冲区T中取出信息存入到本地文件F_out中。实现get、copy、put的操作过程。
功能需求:
l 提供与用户交互的界面,用户可指定输入、输出文件以及缓冲区大小
l 利用信号量实现互斥
l 同时产生多个get、copy和put线程,利用信号量实现多个相同功能的线程间的通信,避免临界资源的非法访问,可参考读写者问题解决方案
l 支持文件输入、输出
非功能需求:
l 程序应有较好的容错性(即能对用户输入的命令进行判断,并对错误的命令进行错误处理)
过程需求:
l 使用vi进行代码的编写
l 使用make工具建立工程
l 将实现不同类别功能的函数写到不同的.c文件中,并使用makefile链接编译。
2 设计说明
2.1 结构设计
三个信号量实现线程互斥
sem_tread_sem; // read
sem_twrite_sem; // write
sem_tcopy_sem; // copy
2.2 功能设计
实现了同步多线程运行,文件读入,缓冲区COPY,文件写入三个线程同时运行,完成LINUX下文件的输入输出。
文件读入:用linux下open(),read(),lseek()函数实现
文件写出:用linux下open(),write()实现
缓冲区建立 malloc()函数
信号量建立sem_init(),sem_wait(),sem_post()
互斥量建立pthread_create(),pthread_mutex_lock(),pthread_mutex_unlock()
3 测试和使用说明
3.1 使用说明
使用./signalmove启动程序,启动参数必须包括,写入文件名,写出的文件名,和缓冲区大小,否则会报错退出。
缓冲区大小必须为数字,否则退出。
4 程序清单
OBJS=main.o copy.o get.o put.o file.o
signalmove:$(OBJS) signalmove.h
gcc $(OBJS) -o signalmove -lpthread
main.o:main.c signalmove.h
gcc -c main.c -lpthread
copy.o:copy.c signalmove.h
gcc -c copy.c
get.o:get.c signalmove.h
gcc -c get.c
put.o:put.c signalmove.h
gcc -c put.c
file.o:file.c signalmove.h
gcc -c file.c
/*
* signalmove.h
*
* Created on: May 14, 2012
* Author: dell
*/
#ifndef SIGNALMOVE_H_
#define SIGNALMOVE_H_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
//file works
void file_in();
void file_out();
//copy from s to t
void copy();
//put and get
void put();
void get();
sem_t read_sem; // read
sem_t write_sem; // write
sem_t copy_sem; // copy
pthread_mutex_t read_mutex; // pthread mutex for read
pthread_mutex_t write_mutex; // pthread mutex for write
char *data_s; //read buffer
char *data_t; //write buffer
int len; //buffer length
char *filename_out; //name_out
char *filename_in; //name_in
int result;
int result_copy;
#endif /* SIGNALMOVE_H_ */
/*
* main.c
*
* Created on: May 14, 2012
* Author: dell
*/
#include "signalmove.h"
int isdigit_all(char *str)
{
while (*str != '\0')
{
if (!isdigit(*str++))
return 0;
}
return 1;
}
//signal out
void Handlesignal(int signo) {
printf("end program!\n", signo);
exit(0);
}
void main(int argc, char* argv[]) {
if(argc!=4){
printf("error input! 1.filename_in,2.filename_out,3,length of buffer\n");
exit(0);
}
if(isdigit_all(argv[3])==0){
printf("error input! 1.filename_in,2.filename_out,3,length of buffer\n");
printf("error length of buffer must be digit!\n");
exit(0);
}
result_copy = 0;
filename_in=argv[1];
filename_out=argv[2];
len=atoi(argv[3]);
int thread_i = 0;
data_s = (char *) malloc(len * sizeof(char));
data_t = (char *) malloc(len * sizeof(char));
if (signal(SIGINT, Handlesignal) == SIG_ERR) {
printf("error signal out\n");
}
pthread_t read_pthread;
pthread_t copy_pthread;
pthread_t write_pthread;
//sem lock
int ini1 = sem_init(&read_sem, 0, 1);
int ini2 = sem_init(&write_sem, 0, 0);
int ini5 = sem_init(©_sem, 0, 0);
if (ini1 && ini2 && ini5 != 0) {
printf("sem error\n");
exit(1);
}
//mutex lock
int ini3 = pthread_mutex_init(&read_mutex, NULL);
int ini4 = pthread_mutex_init(&write_mutex, NULL);
if (ini3 && ini4 != 0) {
printf("mutex error\ n");
exit(1);
}
int thread_1 = pthread_create(&read_pthread, NULL, (void *)&get,
(void *) (&thread_i));
if (thread_1 != 0) {
printf("read thread create error!\n");
exit(1);
}
thread_i++;
int thread_2 = pthread_create(©_pthread, NULL, (void *)©,
(void *) (&thread_i));
if (thread_2 != 0) {
printf("copy thread create error!\n");
exit(1);
}
thread_i++;
int thread_3 = pthread_create(&write_pthread, NULL, (void *)&put,
(void *) (&thread_i));
if (thread_3 != 0) {
printf("write thread create error!\n");
exit(1);
}
pthread_join(read_pthread, NULL);
pthread_join(copy_pthread, NULL);
pthread_join(write_pthread, NULL);
free(data_s);
free(data_t);
exit(0);
}
/*
* file.c
*
* Created on: May 14, 2012
* Author:dell
* file works
*/
#include "signalmove.h"
void file_in(int fd, char *data, int len) {
while (1) {
sem_wait(&read_sem);
pthread_mutex_lock(&read_mutex);
printf("data_in..........\n");
if (lseek(fd, 0, SEEK_CUR) == -1) {
printf("lseek failed!\n");
}
if ((result = read(fd, data, len)) == -1) {
printf("read error! \n");
}
int i=0,j=0;
printf("data_in..........complete\n");
pthread_mutex_unlock(&read_mutex);
sem_post(©_sem);
if(result<len){
len=result;
result=0;
break;
}
}
}
void file_out(int fd, char *data, int len) {
while (1) {
sem_wait(&write_sem);
pthread_mutex_lock(&write_mutex);
printf("data_out..........\n");
if (write(fd, data, len) == -1) {
printf("write error! \n");
}
printf("data_out..........complete\n");
pthread_mutex_unlock(&write_mutex);
if(result_copy==1){
break;
}
}
}
/*
* put.c
*
* Created on: May 14, 2012
* Author: dell
*/
#include "signalmove.h"
void put() {
int fd = open(filename_out, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1) {
printf("open file wrong!\n");
exit(0);
}
file_out(fd, data_t, len);
}
/*
* get.c
*
* Created on: May 14, 2012
* Author: dell
*/
#include "signalmove.h"
void get() {
int fd = open(filename_in, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1) {
printf("open file wrong!\n");
exit(0);
}
file_in(fd, data_s, len);
}
/*
* copy.c
*
* Created on: May 14, 2012
* Author: dell
* copy data from S to T
*/
#include "signalmove.h"
void copy() {
while (1) {
sem_wait(©_sem);
pthread_mutex_lock(&read_mutex);
pthread_mutex_lock(&write_mutex);
printf("copy..........\n");
strcpy(data_t,data_s);
int i=0;
for(;i<len;i++){
data_s[i]=' ';
}
printf("copy..........complete\n");
pthread_mutex_unlock(&write_mutex);
pthread_mutex_unlock(&read_mutex);
sem_post(&write_sem);
sem_post(&read_sem);
if (result == 0) {
result_copy = 1;
break;
}
}
}