作业
1> 使用两个线程完成两个文件的拷贝,主线程拷贝前一半内容,子线程拷贝后一半内容,并且主线程要阻塞回收子线程资源
#include <myhead.h>
typedef struct{
char *src_filename;
char *dst_filename;
int start_pos;
int end_pos;
}copyval,*copyvalPtr;
void copyfile(char *src_file,char *dst_file,int start,int end){
FILE *fp_src = fopen(src_file,"r");
FILE *fp_dst = fopen(dst_file,"a");
if(fp_src == NULL || fp_dst == NULL){
perror("fopen error");
return ;
}
fseek(fp_src,start,SEEK_SET);
fseek(fp_dst,start,SEEK_SET);
char buf[1] = {};
while(ftell(fp_src) < end){
fread(buf,1,1,fp_src);
fwrite(buf,1,1,fp_dst);
}
fclose(fp_src);
fclose(fp_dst);
printf("拷贝成功\n");
}
void *task(void *arg){
copyvalPtr val = (copyval *)arg;
copyfile(val->src_filename,val->dst_filename,val->start_pos,val->end_pos);
pthread_exit(EXIT_SUCCESS);
}
int main(int argc, const char *argv[])
{
char src_file[] = "../1/01.c";
char dst_file[] = "./aaa.txt";
FILE *fp = fopen(src_file,"r");
if(fp == NULL){
perror("fopen error");
return -1;
}
fseek(fp,0,SEEK_END);
int len = ftell(fp);
int end = len;
int mid = end / 2;
copyval val = {src_file,dst_file,mid,end};
pthread_t tid;
int ret = pthread_create(&tid,NULL,task,&val);
if(ret){
printf("pthread_create error\n");
return -1;
}
copyfile(src_file,dst_file,0,mid);
pthread_join(tid,NULL);
fclose(fp);
return 0;
}
效果图:
2> 使用三个进程完成两个文件的拷贝,主线程拷贝前三分之一,子线程1拷贝中间三分之一,子线程2拷贝后三分之一,主线程要设置两个子线程为分离态
#include <myhead.h>
typedef struct{
char *src_filename;
char *dst_filename;
int start_pos;
int end_pos;
}copyval,*copyvalPtr;
void copyfile(char *src_file,char *dst_file,int start,int end){
FILE *fp_src = fopen(src_file,"r");
FILE *fp_dst = fopen(dst_file,"a");
if(fp_src == NULL || fp_dst == NULL){
perror("fopen error");
return ;
}
fseek(fp_src,start,SEEK_SET);
fseek(fp_dst,start,SEEK_SET);
char buf[1] = {};
while(ftell(fp_src) < end){
fread(buf,1,1,fp_src);
fwrite(buf,1,1,fp_dst);
}
fclose(fp_src);
fclose(fp_dst);
printf("拷贝成功\n");
}
void *task1(void *arg){
sleep(3);
copyvalPtr val = (copyval *)arg;
copyfile(val->src_filename,val->dst_filename,val->start_pos,val->end_pos);
pthread_exit(NULL);
}
void *task2(void *arg){
sleep(5);
copyvalPtr val = (copyval *)arg;
copyfile(val->src_filename,val->dst_filename,val->start_pos,val->end_pos);
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
char src_file[] = "../1/01.c";
char dst_file[] = "./bbb.txt";
FILE *fp = fopen(src_file,"r");
if(fp == NULL){
perror("fopen error");
return -1;
}
fseek(fp,0,SEEK_END);
int len = ftell(fp);
int end = len;
int fir_pos = end / 3;
int sec_pos = end / 3 * 2;
copyval val1 = {src_file,dst_file,fir_pos,sec_pos};
copyval val2 = {src_file,dst_file,sec_pos,end};
pthread_t tid1,tid2;
int ret1 = pthread_create(&tid1,NULL,task1,&val1);
int ret2 = pthread_create(&tid2,NULL,task2,&val2);
if(ret1 != 0 || ret2 != 0){
printf("pthread_create error\n");
return -1;
}
pthread_detach(tid1);
pthread_detach(tid2);
copyfile(src_file,dst_file,0,fir_pos);
fclose(fp);
while(1);
return 0;
}
效果图:
三、多线程
3.1 多线程概念
- 多线程(LWP轻量版的进程):线程是更小粒度的单元
- 线程是任务调度的最小单位,进程是资源分配的最小单位
- 线程几乎不占进程的资源,只是占用了很小的有关线程体的相关资源,8k左右
- 多个线程共享进程的资源,所以,线程没有进程安全
- 在一个进程中,至少由一个线程(主线程)
- 线程的切换所消耗的资源比进程切换消耗的少
- 线程所在的进程结束后,该进程中的所有线程全部结束
- 进程中的多个线程的调度方式:时间片轮询,上下文切换,没有先后顺序
3.2 线程的创建(pthread_creat)
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg); //void * (*ptr)(void * , int)
功能:创建一个线程
参数1:线程号(通过地址返回)
参数2:线程的属性,一般写NULL
参数3:线程体函数,是一个函数指针,参数和返回值都为void*类型
参数4:万能指针,是线程体函数的参数
返回值:成功返回0,失败返回错误码,并且线程号不存在
Compile and link with -pthread. //编译时,需要链接pthread库
练习:主线程向子线程传递两个数据,子线程输出这两个数的和
#include<myhead.h>
//定义数据结构体
struct Data
{
int value_1;
int value_2;
};
//定义线程体函数
void *task1(void *arg)
{
//将数据进行解压出来
struct Data data = * (struct Data*)arg;
printf("sum = %d\n", data.value_1+data.value_2);
}
int main(int argc, const char *argv[])
{
int num = 5;
int key = 3;
//定义数据结构体变量
struct Data data = {num, key};
//定义子线程
pthread_t tid;
//创建线程
if(pthread_create(&tid, NULL, task1, &data))
{
printf("线程创建失败\n");
return -1;
}
while(1);
return 0;
}
3.3 线程号的获取(pthread_self)
#include <pthread.h>
pthread_t pthread_self(void);
功能:获取当前线程的线程号
参数:无
返回值:总是成功,返回当前线程的线程号
3.4 线程退出函数(pthread_exit)
1> 不能使用exit或者_exit退出线程,如果在线程体中使用这两个函数,则会直接结束整个进程
2> 可以使用pthread_exit退出某个线程
#include <pthread.h>
void pthread_exit(void *retval);
功能:退出当前线程
参数:退出线程时的状态,一般为NULL
返回值:无
3.5 线程的资源回收(pthread_join)
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
功能:阻塞等待线程的结束并为线程收尸
参数1:线程id
参数2:线程退出时的状态,一般为NULL
返回值:成功返回0,失败返回错误码
3.6 向线程发信号(pthread_cancel)
#include <pthread.h>
int pthread_cancel(pthread_t thread);
功能:向指定的线程发送取消信号,让该线程结束
参数:要取消的线程号
返回值:成功返回0,失败返回非0的错误码
#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
功能:设置线程取消的状态
参数1:要更改的线程状态
PTHREAD_CANCEL_ENABLE:可以接收取消请求(默认)
PTHREAD_CANCEL_DISABLE:不接收取消请求
参数2:旧的状态,一般写NULL
返回值:成功返回0,失败返回非0的错误码
3.7 线程分离(pthread_detach)
#include <pthread.h>
int pthread_detach(pthread_t thread);
功能:将指定的某个线程设置成分离态,设置成分离态的线程,当其结束时,系统会自动回收其资源,无需使用pthread_join来回收
参数:要设置分离态的线程号
返回值:成功返回0,失败返回错误码