#include"myhead.h"\n\n//清除函数\nvoid handler(void *arg)\n{\n\tprintf("[%u] is ended.\n",\n\t\t(unsigned)pthread_self());\n\n\t//解锁\n\tpthread_mutex_unlock((pthread_mutex_t *)arg);\n}\n\n//线程执行函数\nvoid *routine(void *arg)\n{\n\t//1.先接住线程池的地址\n\tthread_pool *pool=(thread_pool *)arg;\n\tstruct task *p;\n\t//2.执行操作\n\twhile(1)\n\t{\n\t\t//2.线程取消例程函数\n\t\t//将来要是有人想取消一个线程,要先把线程拥有的锁解开,再响应取消\n\t\tpthread_cleanup_push(handler,(void *)&pool->lock);\n\t\t//3.上锁,临界资源->任务队列\n\t\tpthread_mutex_lock(&pool->lock);\n\t\t//4.如果当前线程池没有关闭,并且当前线程池没有任务做\n\t\twhile(pool->waiting_tasks == 0 && !pool->shutdown)\n\t\t{\n\t\t\t//那么就进去条件变量中睡觉。\n\t\t\t//printf("[%u] ==>睡\n",(unsigned)pthread_self());\n\t\t\tpthread_cond_wait(&pool->cond, &pool->lock); //线程睡眠,自动解锁\n\t\t\t\n\t\t}\n\t\t//5.要是线程池关闭了,或者有任务做,这些线程就会运行到这行代码\n\t\t//判断当前线程池是不是关闭了,并且没有等待的任务\n\t\tif(pool->waiting_tasks == 0 && pool->shutdown == true)\n\t\t{\t\n\t\t\t//如果线程池关闭,又没有任务做\n\t\t\t//线程那么就会解锁\n\t\t\tpthread_mutex_unlock(&pool->lock);\t\n\t\t\tpthread_exit(NULL); \n\t\t}\n\t\t//6.能运行到这里,说明有任务做\n\t\t//p指向头节点的下一个\n\t\tp = pool->task_list->next;\n\t\t\n\t\t//7.让头节点的指针域指向p的下一个节点\n\t\tpool->task_list->next = p->next;\n\t\t\n\t\t//8.当前任务个数-1\n\t\tpool->waiting_tasks--;\n\t\t\n\t\t//9.解锁\n\t\tpthread_mutex_unlock(&pool->lock);\n\t\t\n\t\t//10.删除线程取消例程函数\n\t\tpthread_cleanup_pop(0);\n\t\t\n\t\t//11.线程要执行任务函数,设置线程不能响应取消\n\t\tpthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); \n\t\t\n\t\t//执行这个p节点指向的节点的函数\n\t\t(p->do_task)(p->arg);\n\t\t\n\t\t//任务函数执行完毕,设置线程能响应取消\n\t\tpthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);\n\t\t\n\t\t//执行完了,释放p对应的空间\n\t\tfree(p);\n\t}\n\tpthread_exit(NULL);\n}\n\n//初始化线程池\nbool init_pool(thread_pool *pool,unsigned int threads_number)\n{\n\t//1.初始化线程池互斥锁\n\tpthread_mutex_init(&pool->lock,NULL);\n\t//2.初始化条件变量\n\tpthread_cond_init(&pool->cond,NULL);\n\t//3.初始化标志位为false,代表当前线程池正在运行\n\tpool->shutdown=false;\n\t//4.初始化任务队列头节点\n\tpool->task_list=malloc(sizeof(struct task));\n\t//5.为存储线程ID号tids申请空间\n\tpool->tids=malloc(sizeof(pthread_t)*MAX_ACTIVE_THREADS);\n\t//6.对第四步和第五步做错误判断\n\tif(pool->task_list==NULL||pool->tids==NULL)\n\t{\n\t\tperror("任务队列|线程号指针 内存失败\n");\n\t\treturn false;\n\t}\n\t//7.为线程池任务队列头节点指针域赋值NULL\n\tpool->task_list->next==NULL;\n\t//8.使用宏定义来设置线程池最大任务个数为1000\n\tpool->max_waiting_tasks=MAX_WAITING_TASKS;\n\t//9.设置当前需要处理任务数位0\n\tpool->waiting_tasks=0;\n\t//10.初始化线程池中线程的个数\n\tpool->active_threads=threads_number;\n\t//11.创建线程\n\tfor(int i=0;iactive_threads;i++)\n\t{\n\t\tif(pthread_create(&(pool->tids[i]),NULL,routine,(void *)pool)!=0)\n\t\t{\n\t\t\tperror("线程创建失败\n");\n\t\t\treturn false;\n\t\t}\n\t}\n\t//12.线程初始化成功,返回true\n\treturn true;\n}\n\n//增添任务\nbool add_task(thread_pool *pool,void *(*do_task)(void *arg),void *arg)\n{\n\t//1.为新任务的节点申请空间\n\tstruct task *new_task=malloc(sizeof(struct task));\n\tif(new_task==NULL)\n\t{\n\t\tperror("新任务申请空间失败\n");\n\t\treturn false;\n\t}\n\t//2.为新节点的数据域与指针域赋值\n\tnew_task->do_task=do_task;\n\tnew_task->arg=arg;\n\tnew_task->next=NULL;\n\t//3.在添加任务到任务队列前,必须先上锁,因为添加任务属于访问临界资源->即任务队列\n\tpthread_mutex_lock(&pool->lock);\n\t//4.如果当前需要等待处理的任务个数已经超过或等于1000,就解锁,并释放掉全部刚刚创建的新节点\n\tif(pool->waiting_tasks>=MAX_WAITING_TASKS)\n\t{\n\t\tpthread_mutex_unlock(&pool->lock);\n\t\tfprintf(stderr,"任务过多\n");\n\t\tfree(new_task);\n\t\treturn false;\n\t}\n\t//5.寻找任务队列中的最后一个节点\n\tstruct task *tmp=pool->task_list;\n\twhile(tmp->next!=NULL)\n\t{\n\t\ttmp=tmp->next;\n\t}\n\t//6.尾插到任务队列中\n\ttmp->next=new_task;\n\t//7.将当前需要等待处理的任务个数+1\n\tpool->waiting_tasks++;\n\t//8.新任务添加完毕,解锁\n\tpthread_mutex_unlock(&pool->lock);\n\t//9.任务已添加,随机唤醒一个条件变量中睡眠的线程起来做任务\n\tpthread_cond_signal(&pool->cond);\n\t//添加成功,唤醒成功,返回true\n\treturn true;\n}\n\n//添加线程\nint add_thread(thread_pool *pool,unsigned additional_threads)\n{\n\t//1.如果创建条数为0,则不添加,直接返回0\n\tif(additional_threads==0)\n\t{\n\t\treturn 0;\n\t}\n\t//2.将初始化的线程个数与新添加的线程个数相加赋值给总线程条数\n\tunsigned total_threads=pool->active_threads+additional_threads;\n\t//3.循环create创建新线程,并将实际创建条数+1,若创建后实际创建成功的线程条数为0,则退出返回-1\n\tint i=0,actual_increment=0;//实际创建条数\n\tfor(i=pool->active_threads;i<total_threads&&i<MAX_ACTIVE_THREADS;i++)\n\t{\n\t\tif(pthread_create(&(pool->tids[i]),NULL,routine,(void *)pool)!=0)\n\t\t{\n\t\t\tperror("新线程创建失败\n");\n\t\t\treturn false;\n\t\t}\n\t}\n\t//4.将实际创建成功个数加入需要等待处理的线程条数\n\tpool->active_threads+=actual_increment;\n\t//5.返回真正创建的条数\n\treturn actual_increment;\n}\n\n//取消删除线程\nint remove_thread(thread_pool *pool,unsigned int removing_threads)\n{\n\t//1.如果想删0条,不给删,直接返回剩余条数\n\tif(removing_threads==0)\n\t{\n\t\treturn pool->active_threads;//这里相当于剩余条数\n\t}\n\t//2.求出取消后剩余线程条数\n\tint remaining_threads=pool->active_threads-removing_threads;\n\tremaining_threads = remaining_threads > 0 ? remaining_threads : 1;\n\t//3.循环取消\n\tint i=0;\n\tfor(i=pool->active_threads-1;i>remaining_threads-1;i--)\n\t{\n\t\terno=pthread_cancel(pool->tids[i]);\n\t\tif(errno!=0)//不为0说明删除失败\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\t//i不变不减小,说明删除失败,然后就返回\n\tif(i==pool->active_threads-1)\n\t{\n\t\treturn -1;\n\t}\n\telse\n\t{\n\t\tpool->active_threads=i+1;//i为下标,下标+1为实际剩余条数\n\t}\n\treturn i+1;//返回删除后剩余条数\n}\n\n//销毁线程池\nbool destroy_pool(thread_pool *pool)\n{\n\t//1.设置线程池为关闭\n\tpool->shutdown=false;\n\t//2.唤醒所有睡眠的线程,目的:方便后续让线程退出\n\tpthread_cond_broadcast(&pool->cond);\n\t//3.结合所有线程\n\tint i=0;\n\tfor(i=0;iactive_threads;i++)\n\t{\n\t\terno=pthread_join(pool->tids[i],NULL);\n\t\tif(errno!=0)//不为0说明接合失败\n\t\t{\n\t\t\tprintf("join tids[%d] error: %s\n",i,strerror(errno));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tprintf("[%u] is joined\n", (unsigned)pool->tids[i]);\n\t\t}\n\t}\n\t//4.释放线程池中动态开辟的一些空间\n\tfree(pool->task_list);\n\tfree(pool->tids);\n\tfree(pool);\n\t//成功销毁,返回true\n\treturn true;\n}\n\n//目录复制\nint copy_any()\n{\n\tchar source_dir[200];//源路径\n\tchar copy_dir[200];//复制地路径\n\tchar source_backdirname[50];//源路径初始文件夹名反序\n\tchar source_dirname[50];//源路径初始文件夹名正序\n\twhile(1)\n\t{\n\t\tbzero(source_dir,sizeof(source_dir));\n\t\tbzero(copy_dir,sizeof(copy_dir));\n\t\tbzero(source_backdirname,sizeof(source_backdirname));\n\t\tbzero(source_dirname,sizeof(source_dirname));\n\t\tprintf("请输入需要复制的源路径:");\n\t\tscanf("%s",source_dir);\n\t\tprintf("请输入复制地路径:");\n\t\tscanf("%s",copy_dir);\n\t\tprintf("源1:%s\n",source_dir);\n\t\tprintf("复制1:%s\n",copy_dir);\n\t\tint j=0;\n\t\tfor(int i=strlen(source_dir)-1;source_dir[i]!='/';i--)//文件夹名反序到source_backdirname中\n\t\t{\n\t\t\tsource_backdirname[j]=source_dir[i];\n\t\t\tj++;\n\t\t}\n\t\tj=0;\n\t\tprintf("strlen(source_backdirname):%ld\n",strlen(source_backdirname));\n\t\tfor(int i=strlen(source_backdirname)-1;i>=0;i--)//正序输入到source_dirname中\n\t\t{\n\t\t\tsource_dirname[j]=source_backdirname[i];\n\t\t\tj++;\n\t\t}\n\t\tstruct file_path *init_path = malloc(sizeof(file_path)); //为文件路径结构体开辟内存空间\n\t\tmemset(init_path,0,sizeof(file_path));//对内存清零 \n\t\tsprintf(init_path->source_path,"%s",source_dir);//拼凑源文件路径\n\t\tsprintf(init_path->copy_path,"%s/%s",copy_dir,source_dirname);//拼凑目标文件路径\n\t\tprintf("源:%s\n",init_path->source_path);\n\t\tprintf("复制:%s\n",init_path->copy_path);\n\t\tcopy_wholedir(init_path);\n\t\tfree(init_path);\n\t\treturn 0;\n\t}\n}\n\n//复制文件夹中单个文件\nvoid *copy_single(void *arg)\n{\n\tstruct file_path *tmp_path=(struct file_path *)arg;\n\tchar buf[10000];\n\tbzero(buf,sizeof(buf));\n\tprintf("源目录单文件:%s\n",tmp_path->source_path);\n\tint fd3=open(tmp_path->source_path,O_RDWR);//打开源文件\n\tif(fd3==-1)\n\t{\n\t\tprintf("源目录中单文件打开失败\n");\n\t\treturn NULL;\n\t}\n\tlong len=lseek(fd3,0,SEEK_END);//读取文件字节总数\n\tlseek(fd3,0,SEEK_SET);//将光标重新移至开头\n\tread(fd3,buf,len);//读取内容,存入buf\n\n\tint fd4=open(tmp_path->copy_path,O_RDWR|O_CREAT,0777);//创建并打开复制文件\n\tif(fd4==-1)\n\t{\n\t\tprintf("复制地目录中单文件打开失败\n");\n\t\treturn NULL;\n\t}\n\twrite(fd4,buf,len);//写入内容\n\tclose(fd3);//关闭文件\n\tclose(fd4);//关闭文件\n\treturn NULL;\n}\n\n//复制整个文件夹\nint copy_wholedir(struct file_path *init_path)\n{\n\tmkdir(init_path->copy_path,0777);\n\tDIR *dp3=opendir(init_path->copy_path);//打开复制地路径目录\n\tif(dp3==NULL)\n\t{\n\t\tprintf("复制地路径不存在,请重新输入\n");\n\t\treturn 0;\n\t}\n\n\tDIR *dp2=opendir(init_path->source_path);//打开源路径目录\n\tif(dp2==NULL)\n\t{\n\t\tprintf("源路径不存在,请重新输入\n");\n\t\treturn 0;\n\t}\n\tchdir(init_path->source_path);//切换到源路径目录\n\tstruct dirent *ep2=NULL;\n\t\n\twhile(1)\n\t{\n\t\tep2 = readdir(dp2);//读取路径下的文件内容\n\t\tif(ep2 == NULL)//读完了也没找到,退出\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tif(ep2->d_name[0] == '.')//去掉.和..\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\t\tstruct file_path *tmp_path = malloc(sizeof(file_path)); //为文件结构体开辟内存空间\n\t\tmemset(tmp_path,0,sizeof(file_path));//对内存清零 \n\t\t\n\t\tsprintf(tmp_path->source_path,"%s/%s",init_path->source_path,ep2->d_name);//拼凑源文件路径\n\t\tsprintf(tmp_path->copy_path,"%s/%s",init_path->copy_path,ep2->d_name);//拼凑目标文件路径\n\t\t\n\t\tif(ep2->d_type==4)\n\t\t{\n\t\t\t//mkdir(tmp_path->copy_path,0777);//在复制地路径下创建与源路径同名文件夹\n\t\t\tcopy_wholedir(tmp_path);\n\t\t\tfree(tmp_path);\n\t\t}\n\t\tif(ep2->d_type==8)\n\t\t{\n\t\t\tprintf("ep2->d_name:%s\n",ep2->d_name);\n\t\t\tprintf("源目录文件为:%s\n",tmp_path->source_path);\n\t\t\t//printf("复制地目录文件为:%s",tmp_path->copy_path);\n\t\t\tadd_task(pool,copy_single,(void *)tmp_path);\n\t\t}\n\t}\n\t//==free(tmp_path);\n\tclosedir(dp2);\n\tclosedir(dp3);\n\treturn 0;\n\