在C中一次运行固定数量的线程

在C中一次运行固定数量的线程,c,multithreading,pthreads,C,Multithreading,Pthreads,我正在尝试使用pthreads将文件从一个目录复制到另一个目录。每个线程只负责复制一个文件。最大线程数通过命令行参数指定 我想做的是,如果当前线程数小于最大线程数,则创建一个线程来执行工作。否则,等待当前线程,当其中一个线程完成时,减少当前线程的数量 我不知道如何通过pthread\u join等待线程而不阻塞主线程 以下是我到目前为止的情况: #include <stdlib.h> #include <stdio.h> #include <dirent.h>

我正在尝试使用
pthreads
将文件从一个目录复制到另一个目录。每个线程只负责复制一个文件。最大线程数通过命令行参数指定

我想做的是,如果当前线程数小于最大线程数,则创建一个线程来执行工作。否则,等待当前线程,当其中一个线程完成时,减少当前线程的数量

我不知道如何通过
pthread\u 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;

}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义MAXNAME 80
#仅定义R_标志
#定义W_标志(O_WRONLY | O_CREAT)
#定义W_PERMS(S_IRUSR | S_IWUSR)
#定义千字节0.001
void*copyfilepass(void*arg);
int main(int argc,char*argv[]){
int num_threads;//要并行执行的线程数
int cur_threads=0;//当前执行的线程数
char filename[MAXNAME];//将临时保留文件名
DIR*source;//指向源目录的指针
DIR*dest;//指向目标目录的指针
struct dirent*dentry;//指向源目录内部结构的指针
struct stat fst;//目录中每个文件的状态
整数误差;
无效*状态;
//***开始错误检查***
如果(argc!=4){
fprintf(stderr,“用法:%s sourceDir destDir numThreads\n”,argv[0]);
返回1;
} 
//检查源目录名是否过长
if(snprintf(文件名,MAXNAME,“%s”,argv[1])==MAXNAME){
fprintf(stderr,“源目录名%s太长,\n”,argv[1]);
返回1;
}
//检查目标目录名是否过长
if(snprintf(文件名,MAXNAME,“%s”,argv[2])==MAXNAME){
fprintf(stderr,“源目录名%s太长,\n”,argv[2]);
返回1;
}
//检查是否可以成功打开源目录
if((source=opendir(argv[1]))==NULL){
fprintf(stderr,“打开源目录%s\n时出错”,argv[1]);
返回1;
}
//检查是否可以成功打开目标目录
if((dest=opendir(argv[2]))==NULL){
fprintf(stderr,“打开目标目录%s\n时出错”,argv[2]);
返回1;
}
//***结束错误检查***
num_threads=atoi(argv[3]);
而((dentry=readdir(source))!=NULL){
//源路径
char*path=(char*)malloc(sizeof(char)*(strlen(dentry->d_name)+strlen(argv[1])+2));//需要''.+'/'+'.\0'
sprintf(路径,“%s%c%s”,argv[1],“/”,dentry->d_name);
//目的地路径
char*dest_path=(char*)malloc(sizeof(char)*(strlen(dentry->d_name)+strlen(argv[2])+2));//需要''.+'/'+'\0'
sprintf(目标路径,“%s%c%s”,argv[2],“/”,dentry->d_名称);
如果(!stat(path,&fst)){//stat()成功,则返回0
if(S_ISREG(fst.st_模式)){
int-args[3];
pthread_t tid;
如果((args[0]=打开(路径,R_标志))=-1){
fprintf(stderr,“未能打开源文件%s:%s\n”,路径,strerror(errno));
继续;
}
if((args[1]=打开(dest_路径、W_标志、W_PERMS))=-1){
fprintf(stderr,“无法打开目标文件%s:%s\n”,目标路径,strerror(errno));
继续;
}
if(当前线程<数量线程){
++cur_螺纹;
if((error=pthread_create(&tid),NULL,copyfilepass,args))){
--cur_螺纹;
fprintf(stderr,“未能创建线程:%s\n”,strerror(错误));
tid=pthread_self();/*不能是新线程的值*/
}
printf(“文件:%.03fKB%s\n”,(fst.st_大小*KB),路径);
}
}
}
}
//关闭目录
closedir(来源);
返回0;
}

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


顺便说一下,使用线程解决这个问题可能不会提高性能,这取决于您操作的文件系统。值得思考。

如果您保留一个线程ID列表,并为线程提供一种方式来指示它们何时终止,您可以避免在它们结束之前加入它们,在这种情况下,
pthread\u join()
应该会立即返回。您可能还希望使用条件变量让主线程在达到最大线程数时等待线程终止。您也可以考虑使用固定数量的线程,并让它们一次一个拷贝(从队列中)复制一个文件,直到没有剩下一个文件,此时,如果主线程阻止它们加入,则是很好的。“……不阻塞主线程”创建另一个线程,通过加入线程来接管线程。拉他们的结果。为此,您需要跟踪所有正在运行的线程。仅一个
pthread\u t
变量将不再执行任何操作。堆内存分配函数(malloc、calloc、realloc)返回的类型为
void*
,因此可以将其分配给任何其他指针。强制转换是不必要的,只会使代码混乱。建议删除对
malloc()
调用的强制转换。发布的代码缺少函数定义:
copyfilepass()
处理完后,代码无法将指向输入和输出文件名路径的指针传递到
free()