在C

时间:2016-10-09 02:19:30

标签: c multithreading pthreads

我正在尝试使用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;

}

1 个答案:

答案 0 :(得分:2)

比产生和收割线程更好的方法是在开始时创建一个固定大小的池,并让它们都从工作队列中消耗掉。这将减少开销并简化代码。

顺便说一下,使用线程来解决这个问题可能无法提高性能,具体取决于您正在操作的文件系统。值得深思。