'#include' 'myhead.h'\n\nstruct thread_pool *pool=NULL;//线程池结构体指针\n\nint fun()\n{\n while(1)\n {\n int a=0;\n printf('= 欢迎来到拷贝系统 =\n');\n printf('= 1.显示文件关系树 =\n');\n printf('= 2.复制单个文件 =\n');\n printf('= 3.复制整个文件夹 =\n');\n printf('= 0.退出系统 =\n');\n printf('请输入命令:');\n scanf('%d',&a);\n switch(a)\n {\n case 1:\n //show_tree();\n break;\n case 2:\n copy_one();\n break;\n case 3:\n copy_any();\n break;\n case 0:\n printf('成功退出\n');\n return 0;\n default:\n printf('命令输入有误,请重新输入\n');\n break;\n }\n }\n}\n\nint main()\n{\n pool = malloc(sizeof(thread_pool));\n init_pool(pool,10);//初始化线程池\n fun();\n destroy_pool(pool);//销毁线程池\n return 0;\n}\n\n//清除函数\nvoid handler(void *arg)\n{\n printf('[%u] is ended.\n',(unsigned)pthread_self());\n\n //解锁\n pthread_mutex_unlock((pthread_mutex_t *)arg);\n}\n\n//线程执行函数\nvoid *routine(void *arg)\n{\n //1.先接住线程池的地址\n thread_pool *pool=(thread_pool *)arg;\n struct task *p;\n //2.执行操作\n while(1)\n {\n //2.线程取消例程函数\n //将来要是有人想取消一个线程,要先把线程拥有的锁解开,再响应取消\n pthread_cleanup_push(handler,(void *)&pool->lock);\n //3.上锁,临界资源->任务队列\n pthread_mutex_lock(&pool->lock);\n //4.如果当前线程池没有关闭,并且当前线程池没有任务做\n while(pool->waiting_tasks == 0 && !pool->shutdown)\n {\n //那么就进去条件变量中睡觉。\n //printf('[%u] ==>睡\n',(unsigned)pthread_self());\n pthread_cond_wait(&pool->cond, &pool->lock); //线程睡眠,自动解锁\n \n }\n //5.要是线程池关闭了,或者有任务做,这些线程就会运行到这行代码\n //判断当前线程池是不是关闭了,并且没有等待的任务\n if(pool->waiting_tasks == 0 && pool->shutdown == true)\n { \n //如果线程池关闭,又没有任务做\n //线程那么就会解锁\n pthread_mutex_unlock(&pool->lock); \n pthread_exit(NULL); \n }\n //6.能运行到这里,说明有任务做\n //p指向头节点的下一个\n p = pool->task_list->next;\n \n //7.让头节点的指针域指向p的下一个节点\n pool->task_list->next = p->next;\n \n //8.当前任务个数-1\n pool->waiting_tasks--;\n \n //9.解锁\n pthread_mutex_unlock(&pool->lock);\n \n //10.删除线程取消例程函数\n pthread_cleanup_pop(0);\n \n //11.线程要执行任务函数,设置线程不能响应取消\n pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); \n \n //执行这个p节点指向的节点的函数\n (p->do_task)(p->arg);\n \n //任务函数执行完毕,设置线程能响应取消\n pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);\n \n //执行完了,释放p对应的空间\n free(p);\n }\n pthread_exit(NULL);\n}\n\n//初始化线程池\nbool init_pool(thread_pool *pool,unsigned int threads_number)\n{\n //1.初始化线程池互斥锁\n pthread_mutex_init(&pool->lock,NULL);\n //2.初始化条件变量\n pthread_cond_init(&pool->cond,NULL);\n //3.初始化标志位为false,代表当前线程池正在运行\n pool->shutdown=false;\n //4.初始化任务队列头节点\n pool->task_list=malloc(sizeof(struct task));\n //5.为存储线程ID号tids申请空间\n pool->tids=malloc(sizeof(pthread_t)*MAX_ACTIVE_THREADS);\n //6.对第四步和第五步做错误判断\n if(pool->task_list==NULL||pool->tids==NULL)\n {\n perror('任务队列|线程号指针 内存失败\n');\n return false;\n }\n //7.为线程池任务队列头节点指针域赋值NULL\n pool->task_list->next==NULL;\n //8.使用宏定义来设置线程池最大任务个数为1000\n pool->max_waiting_tasks=MAX_WAITING_TASKS;\n //9.设置当前需要处理任务数位0\n pool->waiting_tasks=0;\n //10.初始化线程池中线程的个数\n pool->active_threads=threads_number;\n //11.创建线程\n for(int i=0;iactive_threads;i++)\n {\n if(pthread_create(&(pool->tids[i]),NULL,routine,(void *)pool)!=0)\n {\n perror('线程创建失败\n');\n return false;\n }\n }\n //12.线程初始化成功,返回true\n return true;\n}\n\n//增添任务\nbool add_task(thread_pool *pool,void *(*do_task)(void *arg),void *arg)\n{\n //1.为新任务的节点申请空间\n struct task *new_task=malloc(sizeof(struct task));\n if(new_task==NULL)\n {\n perror('新任务申请空间失败\n');\n return false;\n }\n //2.为新节点的数据域与指针域赋值\n new_task->do_task=do_task;\n new_task->arg=arg;\n new_task->next=NULL;\n //3.在添加任务到任务队列前,必须先上锁,因为添加任务属于访问临界资源->即任务队列\n pthread_mutex_lock(&pool->lock);\n //4.如果当前需要等待处理的任务个数已经超过或等于1000,就解锁,并释放掉全部刚刚创建的新节点\n if(pool->waiting_tasks>=MAX_WAITING_TASKS)\n {\n pthread_mutex_unlock(&pool->lock);\n fprintf(stderr,'任务过多\n');\n free(new_task);\n return false;\n }\n //5.寻找任务队列中的最后一个节点\n struct task *tmp=pool->task_list;\n while(tmp->next!=NULL)\n {\n tmp=tmp->next;\n }\n //6.尾插到任务队列中\n tmp->next=new_task;\n //7.将当前需要等待处理的任务个数+1\n pool->waiting_tasks++;\n //8.新任务添加完毕,解锁\n pthread_mutex_unlock(&pool->lock);\n //9.任务已添加,随机唤醒一个条件变量中睡眠的线程起来做任务\n pthread_cond_signal(&pool->cond);\n //添加成功,唤醒成功,返回true\n return true;\n}\n\n//添加线程\nint add_thread(thread_pool *pool,unsigned additional_threads)\n{\n //1.如果创建条数为0,则不添加,直接返回0\n if(additional_threads==0)\n {\n return 0;\n }\n //2.将初始化的线程个数与新添加的线程个数相加赋值给总线程条数\n unsigned total_threads=pool->active_threads+additional_threads;\n //3.循环create创建新线程,并将实际创建条数+1,若创建后实际创建成功的线程条数为0,则退出返回-1\n int i=0,actual_increment=0;//实际创建条数\n for(i=pool->active_threads;i<total_threads&&i<MAX_ACTIVE_THREADS;i++)\n {\n if(pthread_create(&(pool->tids[i]),NULL,routine,(void *)pool)!=0)\n {\n perror('新线程创建失败\n');\n return false;\n }\n }\n //4.将实际创建成功个数加入需要等待处理的线程条数\n pool->active_threads+=actual_increment;\n //5.返回真正创建的条数\n return actual_increment;\n}\n\n//取消删除线程\nint remove_thread(thread_pool *pool,unsigned int removing_threads)\n{\n //1.如果想删0条,不给删,直接返回剩余条数\n if(removing_threads==0)\n {\n return pool->active_threads;//这里相当于剩余条数\n }\n //2.求出取消后剩余线程条数\n int remaining_threads=pool->active_threads-removing_threads;\n remaining_threads = remaining_threads > 0 ? remaining_threads : 1;\n //3.循环取消\n int i=0;\n for(i=pool->active_threads-1;i>remaining_threads-1;i--)\n {\n errno=pthread_cancel(pool->tids[i]);\n if(errno!=0)//不为0说明删除失败\n {\n break;\n }\n }\n //i不变不减小,说明删除失败,然后就返回\n if(i==pool->active_threads-1)\n {\n return -1;\n }\n else\n {\n pool->active_threads=i+1;//i为下标,下标+1为实际剩余条数\n }\n return i+1;//返回删除后剩余条数\n}\n\n//销毁线程池\nbool destroy_pool(thread_pool *pool)\n{\n //1.设置线程池为关闭\n pool->shutdown=false;\n //2.唤醒所有睡眠的线程,目的:方便后续让线程退出\n pthread_cond_broadcast(&pool->cond);\n //3.结合所有线程\n int i=0;\n for(i=0;iactive_threads;i++)\n {\n errno=pthread_join(pool->tids[i],NULL);\n if(errno!=0)//不为0说明接合失败\n {\n printf('join tids[%d] error: %s\n',i,strerror(errno));\n }\n else\n {\n printf('[%u] is joined\n',(unsigned)pool->tids[i]);\n }\n }\n //4.释放线程池中动态开辟的一些空间\n free(pool->task_list);\n free(pool->tids);\n free(pool);\n //成功销毁,返回true\n return true;\n}\n\n//目录复制\nint copy_any()\n{\n char source_dir[200];//源路径\n char copy_dir[200];//复制地路径\n char source_backdirname[50];//源路径初始文件夹名反序\n char source_dirname[50];//源路径初始文件夹名正序\n while(1)\n {\n bzero(source_dir,sizeof(source_dir));\n bzero(copy_dir,sizeof(copy_dir));\n bzero(source_backdirname,sizeof(source_backdirname));\n bzero(source_dirname,sizeof(source_dirname));\n printf('请输入需要复制的源路径:');\n scanf('%s',source_dir);\n printf('请输入复制地路径:');\n scanf('%s',copy_dir);\n printf('源1:%s\n',source_dir);\n printf('复制1:%s\n',copy_dir);\n int j=0;\n for(int i=strlen(source_dir)-1;source_dir[i]!='/';i--)//文件夹名反序到source_backdirname中\n {\n source_backdirname[j]=source_dir[i];\n j++;\n }\n j=0;\n printf('strlen(source_backdirname):%ld\n',strlen(source_backdirname));\n for(int i=strlen(source_backdirname)-1;i>=0;i--)//正序输入到source_dirname中\n {\n source_dirname[j]=source_backdirname[i];\n j++;\n }\n struct file_path *init_path = malloc(sizeof(file_path)); //为文件路径结构体开辟内存空间\n memset(init_path,0,sizeof(file_path));//对内存清零 \n sprintf(init_path->source_path,'%s',source_dir);//拼凑源文件路径\n sprintf(init_path->copy_path,'%s/%s',copy_dir,source_dirname);//拼凑目标文件路径\n printf('源:%s\n',init_path->source_path);\n printf('复制:%s\n',init_path->copy_path);\n copy_wholedir(init_path);\n free(init_path);\n return 0;\n }\n}\n\n//复制文件夹中单个文件\nvoid *copy_single(void *arg)\n{\n struct file_path *tmp_path=(struct file_path *)arg;\n //char buf[10000]; // 原来的代码,使用栈空间\n char *buf = malloc(10000); // 使用堆空间\n if (buf == NULL) {\n perror('内存分配失败\n');\n return NULL;\n }\n bzero(buf,10000); // 清零内存\n printf('源目录单文件:%s\n',tmp_path->source_path);\n int fd3=open(tmp_path->source_path,O_RDWR);//打开源文件\n if(fd3==-1)\n {\n printf('源目录中单文件打开失败\n');\n free(buf); // 释放内存\n return NULL;\n }\n long len=lseek(fd3,0,SEEK_END);//读取文件字节总数\n lseek(fd3,0,SEEK_SET);//将光标重新移至开头\n read(fd3,buf,len);//读取内容,存入buf\n\n int fd4=open(tmp_path->copy_path,O_RDWR|O_CREAT,0777);//创建并打开复制文件\n if(fd4==-1)\n {\n printf('复制地目录中单文件打开失败\n');\n free(buf); // 释放内存\n return NULL;\n }\n write(fd4,buf,len);//写入内容\n close(fd3);//关闭文件\n close(fd4);//关闭文件\n free(buf); // 释放内存\n return NULL;\n}\n\n//复制整个文件夹\nint copy_wholedir(struct file_path *init_path)\n{\n mkdir(init_path->copy_path,0777);\n DIR *dp3=opendir(init_path->copy_path);//打开复制地路径目录\n if(dp3==NULL)\n {\n printf('复制地路径不存在,请重新输入\n');\n return 0;\n }\n\n DIR *dp2=opendir(init_path->source_path);//打开源路径目录\n if(dp2==NULL)\n {\n printf('源路径不存在,请重新输入\n');\n return 0;\n }\n chdir(init_path->source_path);//切换到源路径目录\n struct dirent *ep2=NULL;\n \n while(1)\n {\n ep2 = readdir(dp2);//读取路径下的文件内容\n if(ep2 == NULL)//读完了也没找到,退出\n {\n break;\n }\n if(ep2->d_name[0] == '.')//去掉.和..\n {\n continue;\n }\n struct file_path *tmp_path = malloc(sizeof(file_path)); //为文件结构体开辟内存空间\n memset(tmp_path,0,sizeof(file_path));//对内存清零 \n \n sprintf(tmp_path->source_path,'%s/%s',init_path->source_path,ep2->d_name);//拼凑源文件路径\n sprintf(tmp_path->copy_path,'%s/%s',init_path->copy_path,ep2->d_name);//拼凑目标文件路径\n\n if(ep2->d_type==4)\n {\n //mkdir(tmp_path->copy_path,0777);//在复制地路径下创建与源路径同名文件夹\n copy_wholedir(tmp_path);\n free(tmp_path);\n }\n if(ep2->d_type==8)\n {\n printf('ep2->d_name:%s\n',ep2->d_name);\n printf('源目录文件为:%s\n',tmp_path->source_path);\n //printf('复制地目录文件为:%s',tmp_path->copy_path);\n add_task(pool,copy_single,(void *)tmp_path);\n }\n }\n //==free(tmp_path);\n closedir(dp2);\n closedir(dp3);\n}\n

C语言线程池实现大目录拷贝优化 - 解决栈溢出问题

原文地址: https://www.cveoy.top/t/topic/ojLk 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录