我正在尝试使用pthreads
将文件从一个目录复制到另一个目录。每个线程负责复制一个文件。最大线程数通过命令行参数指定。
我想要做的是如果当前线程小于最大线程,则创建一个线程来完成工作。 ELSE,等待当前线程,当其中一个完成时,减少当前线程数。
我无法弄清楚如何通过pthread_join
等待线程而不会阻塞主线程。
这是我到目前为止所做的:
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#define MAXNAME 80
#define R_FLAGS O_RDONLY
#define W_FLAGS (O_WRONLY | O_CREAT)
#define W_PERMS (S_IRUSR | S_IWUSR)
#define KILOBYTE 0.001
void *copyfilepass(void *arg);
int main(int argc, char* argv[]){
int num_threads; //number of threads to execute in parallel
int cur_threads = 0; //number of threads currently executing
char filename[MAXNAME]; //will temporarily hold the file name
DIR* source; //pointer to the source directory
DIR* dest; //pointer to the destination directory
struct dirent* dentry; //pointer to the internal structure of the source directory
struct stat fst; //stats for each file in a directory
int error;
void *status;
//***BEGIN ERROR CHECKING***
if (argc != 4) {
fprintf(stderr, "Usage: %s sourceDir destDir numThreads\n", argv[0]);
return 1;
}
//check if source directory name is too long
if ( snprintf(filename, MAXNAME, "%s", argv[1]) == MAXNAME ) {
fprintf(stderr, "Source directory name %s too long\n", argv[1]);
return 1;
}
//check if destination directory name is too long
if ( snprintf(filename, MAXNAME, "%s", argv[2]) == MAXNAME ) {
fprintf(stderr, "Source directory name %s too long\n", argv[2]);
return 1;
}
//check if we can successfully open the source directory
if( (source = opendir(argv[1])) == NULL ) {
fprintf(stderr, "Error opening source directory %s\n", argv[1]);
return 1;
}
//check if we can successfully open the destination directory
if( (dest = opendir(argv[2])) == NULL ) {
fprintf(stderr, "Error opening destination directory %s\n", argv[2]);
return 1;
}
//***END ERROR CHECKING***
num_threads = atoi(argv[3]);
while( (dentry = readdir(source)) != NULL ){
//source path
char* path = (char*)malloc(sizeof(char) * (strlen(dentry->d_name) + strlen(argv[1]) + 2)); //need '.' + '/' + '\0'
sprintf(path, "%s%c%s", argv[1], '/', dentry->d_name);
//destination path
char* dest_path = (char*)malloc(sizeof(char) * (strlen(dentry->d_name) + strlen(argv[2]) + 2)); //need '.' + '/' + '\0'
sprintf(dest_path, "%s%c%s", argv[2], '/', dentry->d_name);
if(!stat(path, &fst)){ //stat() return 0 if successful
if(S_ISREG(fst.st_mode)){
int args[3];
pthread_t tid;
if ( (args[0] = open(path, R_FLAGS)) == -1 ) {
fprintf(stderr, "Failed to open source file %s: %s\n", path, strerror(errno));
continue;
}
if ( (args[1] = open(dest_path, W_FLAGS, W_PERMS)) == -1 ) {
fprintf(stderr, "Failed to open destination file %s: %s\n", dest_path, strerror(errno));
continue;
}
if(cur_threads < num_threads) {
++cur_threads;
if ( (error = pthread_create((&tid), NULL, copyfilepass, args)) ) {
--cur_threads;
fprintf(stderr, "Failed to create thread: %s\n", strerror(error));
tid = pthread_self(); /* cannot be value for new thread */
}
printf("file: %.03fKB %s\n", (fst.st_size * KILOBYTE), path);
}
}
}
}
//close directory
closedir(source);
return 0;
}
答案 0 :(得分:2)
比产生和收割线程更好的方法是在开始时创建一个固定大小的池,并让它们都从工作队列中消耗掉。这将减少开销并简化代码。
顺便说一下,使用线程来解决这个问题可能无法提高性能,具体取决于您正在操作的文件系统。值得深思。