Linux 线程并发拷贝,【Linux】线程并发拷贝程序
據(jù)說大連某211高校的李教授越來越重口,不僅延續(xù)要求他所帶的每一個本科班,都要寫一份線程并發(fā)拷貝程序的傳統(tǒng),而且還開始規(guī)定不能用Java語言寫作,導致我之前寫的《【Java】線程并發(fā)拷貝程序》(點擊打開鏈接)作廢。所有李教授旗下的學生,必須在毫無圖形界面的Linux系統(tǒng),用里面vi去寫作。這更讓莘莘學子們感覺本來頭來就不光明的天空更加黑暗起來。
更重要的是,若干年過去了,網(wǎng)上對其的研究與資料,依舊是少數(shù),依舊是那份流傳已久,以訛傳訛的C語言版。
雖然這個程序毫無研究價值,但是本著治病救人,同時借此深入研究LinuxC的線程編程機制,我再一次完成了這份,在Linux用最最最純種C語言完成的線程并發(fā)拷貝程序。
如下圖,搞了3個線程在Linux系統(tǒng)下完成文件夾A中的所有內(nèi)容到空空是也文件夾B的復制。同時按照李教授的喜好,在前面補個前綴,也就是重命名目標文件夾。
可能有些同學說我上面的圖形化的Linux系統(tǒng)與無圖形化的Linux是不同的。
其實上述代碼在各個版本的Linux系統(tǒng)都可以運行的,只是你寫C語言要用《【Linux】vi/vim的使用》(點擊打開鏈接)去寫,查詢文件與文件夾,要用cd命令先進入相關(guān)的路徑,同時用dir命令讀這個文件夾目錄。要是你覺得vi難用,可以用《【Linux】用Winscp遠程訪問無圖形界面的Linux系統(tǒng)》(點擊打開鏈接),將你在windows下寫好的代碼,傳上Linux,再用gcc編譯再運行。
具體代碼如下:
#include
#include
#include
#include//輸出文件信息
#include//判斷是否目錄
#include//使用線程
char *source_arr[512];//存放源文件路徑的數(shù)組
char *destination_arr[512];//存放目標文件路徑的數(shù)組
int source_arr_index=0;//存放源文件路徑的數(shù)組的索引,就是for(int i=xx;..;..)那個i
int destination_arr_index=0;//存放目標文件路徑的數(shù)組的索引
pthread_mutex_t mutex;//聲明一個互斥鎖mutex
int i=0;//多個線程函數(shù)用到這個i,用于記錄是否復制完畢,因此作為全局變量處理~
/*字符串處理函數(shù)*/
int endwith(char* s,char c){//用于判斷字符串結(jié)尾是否為“/”與“.”
if(s[strlen(s)-1]==c){
return 1;
}
else{
return 0;
}
}
char* str_contact(char* str1,char* str2){//字符串連接
char* result;
result=(char*)malloc(strlen(str1)+strlen(str2)+1);//str1的長度+str2的長度+\0;
if(!result){//如果內(nèi)存動態(tài)分配失敗
printf("字符串連接時,內(nèi)存動態(tài)分配失敗\n");
exit(1);
}
strcat(result,str1);
strcat(result,str2);//字符串拼接
return result;
}
/*遍歷函數(shù)*/
int is_dir(char* path){//判斷是否是目錄
struct stat st;
stat(path,&st);
if(S_ISDIR(st.st_mode)){
return 1;
}
else{
return 0;
}
}
void read_folder(char* source_path,char *destination_path){//復制文件夾
if(!opendir(destination_path)){
if (mkdir(destination_path,0777))//如果不存在就用mkdir函數(shù)來創(chuàng)建
{
printf("創(chuàng)建文件夾失敗!");
}
}
char *path;
path=(char*)malloc(512);//相當于其它語言的String path="",純C環(huán)境下的字符串必須自己管理大小,這里為path直接申請512的位置的空間,用于目錄的拼接
path=str_contact(path,source_path);//這三句,相當于path=source_path
struct dirent* filename;
DIR* dp=opendir(path);//用DIR指針指向這個文件夾
while(filename=readdir(dp)){//遍歷DIR指針指向的文件夾,也就是文件數(shù)組。
memset(path,0,sizeof(path));
path=str_contact(path,source_path);
//如果source_path,destination_path以路徑分隔符結(jié)尾,那么source_path/,destination_path/直接作路徑即可
//否則要在source_path,destination_path后面補個路徑分隔符再加文件名,誰知道你傳遞過來的參數(shù)是f:/a還是f:/a/啊?
char *file_source_path;
file_source_path=(char*)malloc(512);
file_source_path=str_contact(file_source_path,source_path);
if(!endwith(source_path,'/')){
file_source_path=str_contact(source_path,"/");
}
char *file_destination_path;
file_destination_path=(char*)malloc(512);
file_destination_path=str_contact(file_destination_path,destination_path);
if(!endwith(destination_path,'/')){
file_destination_path=str_contact(destination_path,"/");
}
//取文件名與當前文件夾拼接成一個完整的路徑
file_source_path=str_contact(file_source_path,filename->d_name);
if(is_dir(file_source_path)){//如果是目錄
if(!endwith(file_source_path,'.')){//同時并不以.結(jié)尾,因為Linux在所有文件夾都有一個.文件夾用于連接上一級目錄,必須剔除,否則進行遞歸的話,后果無法想象!
file_destination_path=str_contact(file_destination_path,filename->d_name);//對目標文件夾的處理,取文件名與當前文件夾拼接成一個完整的路徑
read_folder(file_source_path,file_destination_path);//進行遞歸調(diào)用,相當于進入這個文件夾進行遍歷~
}
}
else{//否則,將源文件于目標文件的路徑分別存入相關(guān)數(shù)組
//對目標文件夾的處理,取文件名與當前文件夾拼接成一個完整的路徑
file_destination_path=str_contact(file_destination_path,"前綴_");//給目標文件重命名,這里示意如何加個前綴~^_^
file_destination_path=str_contact(file_destination_path,filename->d_name);
source_arr[source_arr_index]=file_source_path;
source_arr_index++;
destination_arr[destination_arr_index]=file_destination_path;
destination_arr_index++;
}
}
}
/*復制函數(shù)*/
void copy_file(char* source_path,char *destination_path){//復制文件
char buffer[1024];
FILE *in,*out;//定義兩個文件流,分別用于文件的讀取和寫入int len;
if((in=fopen(source_path,"r"))==NULL){//打開源文件的文件流
printf("源文件打開失敗!\n");
exit(1);
}
if((out=fopen(destination_path,"w"))==NULL){//打開目標文件的文件流
printf("目標文件創(chuàng)建失敗!\n");
exit(1);
}
int len;//len為fread讀到的字節(jié)長
while((len=fread(buffer,1,1024,in))>0){//從源文件中讀取數(shù)據(jù)并放到緩沖區(qū)中,第二個參數(shù)1也可以寫成sizeof(char)
fwrite(buffer,1,len,out);//將緩沖區(qū)的數(shù)據(jù)寫到目標文件中
}
fclose(out);
fclose(in);
}
/*線程執(zhí)行函數(shù)*/
void *thread_function(void *arg){
while(i
if(pthread_mutex_lock(&mutex)!=0){//對互斥鎖上鎖,臨界區(qū)開始
printf("%s的互斥鎖創(chuàng)建失敗!\n",(char *)arg);
pthread_exit(NULL);
}
if(i
copy_file(source_arr[i],destination_arr[i]);//復制單一文件
printf("%s復制%s到%s成功!\n",(char *)arg,source_arr[i],destination_arr[i]);
i++;
sleep(1);//該線程掛起1秒
}
else{//否則退出
pthread_exit(NULL);//退出線程
}
pthread_mutex_unlock(&mutex);//解鎖,臨界區(qū)結(jié)束
sleep(1);//該線程掛起1秒
}
pthread_exit(NULL);//退出線程
}
/*主函數(shù)*/
int main(int argc,char *argv[]){
if(argv[1]==NULL||argv[2]==NULL){
printf("請輸入兩個文件夾路徑,第一個為源,第二個為目的!\n");
exit(1);
}
char* source_path=argv[1];//取用戶輸入的第一個參數(shù)
char* destination_path=argv[2];//取用戶輸入的第二個參數(shù)
DIR* source=opendir(source_path);
DIR* destination=opendir(destination_path);
if(!source||!destination){
printf("你輸入的一個參數(shù)或者第二個參數(shù)不是文件夾!\n");
}
read_folder(source_path,destination_path);//進行文件夾的遍歷
/*線程并發(fā)開始*/
pthread_mutex_init(&mutex,NULL);//初始化這個互斥鎖
//聲明并創(chuàng)建三個線程
pthread_t t1;
pthread_t t2;
pthread_t t3;
if(pthread_create(&t1,NULL,thread_function,"線程1")!=0){
printf("創(chuàng)建線程失敗!程序結(jié)束!\n");
exit(1);
}
if(pthread_create(&t2,NULL,thread_function,"線程2")!=0){
printf("創(chuàng)建線程失敗!程序結(jié)束!\n");
exit(1);
}
if(pthread_create(&t3,NULL,thread_function,"線程3")!=0){
printf("創(chuàng)建線程失敗!程序結(jié)束!\n");
exit(1);
}
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_join(t3,NULL);
//三個線程都完成才能執(zhí)行以下的代碼
pthread_mutex_destroy(&mutex);//銷毀這個互斥鎖
/*線程并發(fā)結(jié)束*/
return 0;
}
這百來行代碼,也沒有什么好說的。
首先這個程序是《【Linux】線程互斥》(點擊打開鏈接)與《【Linux】C語言實現(xiàn)文件夾拷貝》(點擊打開鏈接)的結(jié)合體。里面涉及的概念,我已經(jīng)在這兩篇文件都詳細寫了,這里就不再大篇幅敘述了。
之后,由于涉及大量路徑的拼接,搞到最后還是《【Linux】純C環(huán)境下字符串的處理》(點擊打開鏈接)問題,C語言就是這么煩,搞個字符串,要用到指針、數(shù)組、函數(shù),等各種大量復雜的概念去處理。
總結(jié)
以上是生活随笔為你收集整理的Linux 线程并发拷贝,【Linux】线程并发拷贝程序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 命令及串口命令_嵌入式Linux系列第7
- 下一篇: matlab cell计算,MATLAB