1.多线程
1.1多线程概念
多线程(LWP):线程是进程的更小粒度的单元,进程是分配资源的最小单位,而线程是调度的最小单位,线程共享进程的资源。线程几乎不占用资源,只是占用了很少的程序执行的状态的资源(8k)。线程由于共用进程的资源,所以多线程没有多进程安全。多线程的切换要比多进程的切换开销小。在一个进程内至少会有一个线程(主线程)。线程的所有的函数都调用的是第三方库,所以在使用前需要先安装线程函数的man手册。
sudo apt-get install manpages-posix manpages-posix-dev
1.2多线程创建(pthread_create)
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
功能:创建线程
参数:
@thread:返回的是创建的线程号
@attr: 线程属性默认是NULL
@start_routine:线程体
void *(*start_routine) (void *)
@arg:向线程体传递的参数
返回值:成功返回0,失败返回错误码
注:由于线程是第三方的库函数,所以编译的时候需要链接如下的库
Compile and link with -lpthread.
#include <head.h>
void *task1(void *arg)
{
//线程的处理函数
printf("这是线程1....\n");
}
int main(int argc, const char *argv[])
{
pthread_t tid;
if (pthread_create(&tid, NULL, task1, NULL))
PRINT_ERR("pthread create error");
printf("这里是主线程...\n");
while(1); //这里加while(1)的目的,让进程不退出,因为进入退出了,线程就退出了
return 0;
}
1.3多线程内存问题
多线程共用进程的资源
#include <head.h>
int money = 5000;
void *task1(void *arg)
{
money = money - 50;
printf("任务1取了50块钱,剩余=%d\n", money);
}
void *task2(void *arg)
{
sleep(2);
money = money - 100;
//任务2是在任务1的基础上将money减去了100,相当于task1和task2在共用同一块内存
printf("任务2取了100块钱,剩余=%d\n", money);
}
int main(int argc, const char *argv[])
{
pthread_t tid1, tid2;
if (pthread_create(&tid1, NULL, task1, NULL))
PRINT_ERR("create tid1 error");
if (pthread_create(&tid2, NULL, task2, NULL))
PRINT_ERR("create tid1 error");
printf("tid1=%#lx,tid2=%#lx\n", tid1, tid2);
while (1)
;
return 0;
}
1.4多线程执行顺序
多线程执行没有先后顺序,时间片轮询,上下文切换
1.5多线程获取线程ID (pthread_self)
pthread_t pthread_self(void);
功能:获取当前线程的线程号
参数:
@无
返回值:当前线程的tid
#include <head.h>
void *task1(void *arg)
{
//pthread_t ptid = (pthread_t)*arg; //错误的写法
pthread_t ptid = *(pthread_t *)arg;
// sleep(1);
//线程的处理函数
printf("tid = %#lx,ptid = %#lx这是线程1....\n",pthread_self(),ptid);
}
int main(int argc, const char *argv[])
{
pthread_t tid;
pthread_t ptid;
ptid=pthread_self();
//向线程传参ptid
if (pthread_create(&tid, NULL, task1, (void *)&ptid))
PRINT_ERR("pthread create error");
printf("child tid = %#lx,这里是主线程...\n",tid);
printf("parent tid = %#lx\n",ptid);
while(1);
return 0;
}
1.6多线程退出(pthread_exit)
注:不能使用exit/_exit退出线程,因为这两个函数的功能是结束进程的,因为进程退出后,所有的线程都会结束
#include <head.h>
int money = 5000;
void *task1(void *arg)
{
money = money - 50;
printf("任务1取了50块钱,剩余=%d\n", money);
exit(EXIT_SUCCESS);
//_exit(EXIT_SUCCESS);
//注:在线程中,不能使用exit/_exit退出线程,因为
//exit/_exit是用来退出进程的,进程退出整个程序就结束了
}
int main(int argc, const char *argv[])
{
pthread_t tid1;
if (pthread_create(&tid1, NULL, task1, NULL))
PRINT_ERR("create tid1 error");
printf("tid1=%#lx\n", tid1);
while (1){
printf("11111111111\n");
sleep(1);
}
return 0;
}
#include <pthread.h>
void pthread_exit(void *retval);
功能:退出一个线程
参数:
@retval:退出的状态
返回值:无
#include <head.h>
int money = 5000;
void *task1(void *arg)
{
sleep(6);
money = money - 50;
printf("任务1取了50块钱,剩余=%d\n", money);
pthread_exit(NULL); //退出线程
}
int main(int argc, const char *argv[])
{
pthread_t tid1;
if (pthread_create(&tid1, NULL, task1, NULL))
PRINT_ERR("create tid1 error");
printf("tid1=%#lx\n", tid1);
while (1){
printf("11111111111\n");
sleep(1);
}
return 0;
}
1.7多线程资源回收(pthread_join)
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
功能:阻塞等待线程结束,并为线程收尸
参数:
@thread:线程ID
@retval:退出时候返回的状态值
返回值:成功返回0,失败返回错误码
#include <head.h>
int money = 5000;
void *task1(void *arg)
{
money = money - 50;
printf("任务1取了50块钱,剩余=%d\n", money);
pthread_exit(NULL);
}
void *task2(void *arg)
{
sleep(2);
money = money - 100;
printf("任务2取了100块钱,剩余=%d\n", money);
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
pthread_t tid1, tid2;
if (pthread_create(&tid1, NULL, task1, NULL))
PRINT_ERR("create tid1 error");
if (pthread_create(&tid2, NULL, task2, NULL))
PRINT_ERR("create tid1 error");
printf("tid1=%#lx,tid2=%#lx\n", tid1, tid2);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}
1.8多线程发信号(pthread_cancel)
int pthread_cancel(pthread_t thread);
功能:一个线程给另外一个线程发送取消的信号(结束线程的执行)
参数:
@thread:线程id
返回值:成功返回0,失败返回错误码
#include <head.h>
int money = 5000;
void *task1(void *arg)
{
//功能,让线程不关系cancel的信号,这样线程将永远执行下去
//pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
while(1){
printf("i am task1...\n");
sleep(1);
}
pthread_exit(NULL);
}
void *task2(void *arg)
{
pthread_t tid1=*(pthread_t *)arg;
sleep(3);
//在线程2中3秒后给线程1发送结束的信号,线程1就结束掉了
pthread_cancel(tid1);
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
pthread_t tid1, tid2;
if (pthread_create(&tid1, NULL, task1, NULL))
PRINT_ERR("create tid1 error");
if (pthread_create(&tid2, NULL, task2, (void *)&tid1))
PRINT_ERR("create tid2 error");
printf("tid1=%#lx,tid2=%#lx\n", tid1, tid2);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}
1.9多线程分离态(pthread_detach)
线程有两种状态:结合态和分离态,默认线程的状态为结合态,结合态的线程需要调用pthread_join来回收资源,如果将线程标记为分离态,当线程执行接受后资源会被自动回收。
int pthread_detach(pthread_t thread);
功能:将线程标记为分离态
参数:
@thread:线程的tid
返回值:成功返回0,失败返回错误码
#include <head.h>
int money = 5000;
void *task1(void *arg)
{
sleep(1);
printf("i am task1...\n");
pthread_exit(NULL);
}
void *task2(void *arg)
{
sleep(2);
printf("i am task2...\n");
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
pthread_t tid1, tid2;
if (pthread_create(&tid1, NULL, task1, NULL))
PRINT_ERR("create tid1 error");
if (pthread_create(&tid2, NULL, task2, (void *)&tid1))
PRINT_ERR("create tid2 error");
printf("tid1=%#lx,tid2=%#lx\n", tid1, tid2);
//在主线程中标记线程1和线程2位分离态,
//分离态的线程结束后资源会被自动回收,这个函数不会阻塞
pthread_detach(tid1);
pthread_detach(tid2);
while(1);
return 0;
}
2.多线程互斥
2.1多线程竞态的现象如下
#include <head.h>
int money = 5000;
void *task1(void *arg)
{
while (1)
{
money = money - 50;
if (money > 0)
{
printf("张三取了50块钱,剩余=%d\n", money);
}
else
{
pthread_exit(NULL);
}
sleep(1);
}
}
void *task2(void *arg)
{
while (1)
{
money = money - 100;
if (money > 0)
{
printf("李四取了100块钱,剩余=%d\n", money);
}
else
{
pthread_exit(NULL);
}
sleep(1);
}
}
int main(int argc, const char *argv[])
{
pthread_t tid1, tid2;
if (pthread_create(&tid1, NULL, task1, NULL))
PRINT_ERR("create tid1 error");
if (pthread_create(&tid2, NULL, task2, NULL))
PRINT_ERR("create tid1 error");
printf("tid1=%#lx,tid2=%#lx\n", tid1, tid2);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}
在上述程序执行的时候,张三和李四在某次取钱的时候是同时在操作的,就会出现竞态的现象,所以如果想解决这种问题,一定要用到多线的互斥,一个线程在操作这个money变量的时候,另外一个线程不能够操作的这个全局变量。(注这个变量又叫做临界资源)
2.2什么是多线程互斥
多线程互斥:互斥是多个线程争抢临界资源的过程,只要抢占成功就可以操作临界资源,如果没有抢占成功就不能够操作这个临界资源,这里没有体现顺序执行的概念,可能某个线程执行多次之后另外一个线程在执行一次。但是在其中一个线程执行的时候另外一个线程一定不能执行的,这个就是互斥。这个互斥可以通过线程互斥锁完成。
2.3线程互斥锁API
#include <pthread.h>
1.定义互斥锁的变量
pthread_mutex_t mutex;
2.初始化线程互斥锁
int pthread_mutex_init(pthread_mutex_t * mutex,
const pthread_mutexattr_t * attr);
//动态初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//静态初始化
功能:初始化线程的互斥锁
参数:
@mutex:互斥锁变量的地址
@attr:缺省属性,默认填写为NULL
返回值:成功返回0,失败返回错误码
3.上锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
//如果获取不到资源,不会阻塞,立即返回
功能:上锁(如果互斥锁可用直接能占用锁,如果互斥锁不可用将会阻塞等待)
参数:
@mutex:互斥锁变量的地址
返回值:成功返回0,失败返回错误码
4.解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:解锁
参数:
@mutex:互斥锁变量的地址
返回值:成功返回0,失败返回错误码
5.销毁互斥锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:销毁互斥锁
参数:
@mutex:互斥锁变量的地址
返回值:成功返回0,失败返回错误码
2.4线程互斥的实例
#include <head.h>
//1.定义互斥锁变量
//pthread_mutex_t mutex;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int money = 5000;
void *task1(void *arg)
{
while (1)
{
pthread_mutex_lock(&mutex);
money = money - 50;
if (money > 0)
{
printf("张三取了50块钱,剩余=%d\n", money);
}
else
{
printf("张三取钱的线程1退出...\n");
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
void *task2(void *arg)
{
while (1)
{
pthread_mutex_lock(&mutex);
money = money - 100;
if (money > 0)
{
printf("李四取了100块钱,剩余=%d\n", money);
}
else
{
printf("李四取钱的线程2退出...\n");
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main(int argc, const char *argv[])
{
pthread_t tid1, tid2;
//2.初始化线程互斥锁
//pthread_mutex_init(&mutex,NULL);
if (pthread_create(&tid1, NULL, task1, NULL))
PRINT_ERR("create tid1 error");
if (pthread_create(&tid2, NULL, task2, NULL))
PRINT_ERR("create tid1 error");
printf("tid1=%#lx,tid2=%#lx\n", tid1, tid2);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
//5.销毁锁
pthread_mutex_destroy(&mutex);
return 0;
}
3.多线程同步
3.1什么是同步?
线程同步:线程同步就是已经知道线程执行的顺序,并且线程是顺序执行的。线程同步适合用于生产者消费者模型。例如线程1生产一辆车,线程2购买这辆车。所以线程执行的时候就必须线程1执行线程2在执行。
3.2线程同步之无名信号量
3.2.1无名信号量的API
#include <semaphore.h>
1.定义无名信号量
sem_t sem;
2.初始化信号
int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:初始化信号量
参数:
@sem:结构体指针
@pshared:
0:多线程间
1:进程间
@value:信号量的值,如果填写为1,能获取到信号量,如果是0获取不到信号量
返回值:成功返回0,失败返回-1置位错误码
3.申请资源
int sem_wait(sem_t *sem);
功能:申请资源,(P操作 -1),如果申请不到资源就阻塞等待
参数:
@sem:结构体指针
返回值:成功返回0,失败返回-1置位错误码
4.释放资源
int sem_post(sem_t *sem);
功能:释放资源,(V操作 +1)
参数:
@sem:结构体指针
返回值:成功返回0,失败返回-1置位错误码
5.销毁信号量
int sem_destroy(sem_t *sem);
功能:销毁信号量
参数:
@sem:结构体指针
返回值:成功返回0,失败返回-1置位错误码
3.2.2无名信号量实现线程同步的实例
#include <head.h>
#include <semaphore.h>
//1.定义信号量
sem_t sem;
void *task1(void *arg)
{
int num = 5;
while (num--)
{
sleep(2);
printf("生产了一辆超级跑车\n");
sem_post(&sem); //4.释放资源
}
pthread_exit(NULL);
}
void *task2(void *arg)
{
int num = 5;
while (num--)
{
//由于没有资源,这个sem_wait阻塞等待
sem_wait(&sem); //3.申请资源
printf("我购买了一辆超级跑车\n");
}
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
pthread_t tid1, tid2;
//2.初始化无名信号量,初始化的时候value=0
sem_init(&sem, 0, 0);
if (pthread_create(&tid1, NULL, task1, NULL))
PRINT_ERR("create tid1 error");
if (pthread_create(&tid2, NULL, task2, NULL))
PRINT_ERR("create tid1 error");
printf("tid1=%#lx,tid2=%#lx\n", tid1, tid2);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
//5.销毁无名信号量
sem_destroy(&sem);
return 0;
}
3.2.3练习无名信号量实现同步过程
要求:创建三个线程,其中这个三个线程分别打印A、B、C,通过无名信号量实现如下的打印过程
ABCABCABC…
#include <head.h>
#include <semaphore.h>
// 1.定义信号量
sem_t sem1, sem2, sem3;
void *task1(void *arg)
{
int num = 5;
while (num--)
{
sem_wait(&sem1);
fprintf(stderr, "A");
sem_post(&sem2); // 4.释放资源
}
pthread_exit(NULL);
}
void *task2(void *arg)
{
int num = 5;
while (num--)
{
sem_wait(&sem2);
fprintf(stderr, "B");
sem_post(&sem3); // 4.释放资源
}
pthread_exit(NULL);
}
void *task3(void *arg)
{
int num = 5;
while (num--)
{
sem_wait(&sem3);
fprintf(stderr, "C");
sem_post(&sem1); // 4.释放资源
}
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
pthread_t tid1, tid2, tid3;
// 2.初始化无名信号量,初始化的时候value=0
sem_init(&sem1, 0, 1);
sem_init(&sem2, 0, 0);
sem_init(&sem3, 0, 0);
if (pthread_create(&tid1, NULL, task1, NULL))
PRINT_ERR("create tid1 error");
if (pthread_create(&tid2, NULL, task2, NULL))
PRINT_ERR("create tid1 error");
if (pthread_create(&tid3, NULL, task3, NULL))
PRINT_ERR("create tid1 error");
// printf("tid1=%#lx,tid2=%#lx,tid3=%#lx\n", tid1, tid2, tid3);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);
printf("\n");
// 5.销毁无名信号量
sem_destroy(&sem1);
sem_destroy(&sem2);
sem_destroy(&sem3);
return 0;
}
3.3线程同步之条件变量
在Linux系统上如果有多个线程需要实现同步,使用无名信号量会比较繁琐,因为只要有一个线程就要定义一个无名信号量。所以在多个线程需要同步的时候Linux开发者就设计了一个添加变量的机制完成这些线程的同步过程。
3.3.1条件变量的API
1.定义条件变量
pthread_cond_t cond;
2.初始化条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//静态初始化
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
功能:动态初始化一个条件变量
参数:
@cond:条件变量的指针
@attr:NULL使用默认属性
返回值:成功返回0,失败返回非0
3.阻塞等待条件变量
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
功能:阻塞等待条件变量,在条件变量中维护了一个队列,
这里的互斥锁就是为了解决在往队列中放线程的时候出现竞态问题的。
使用的步骤:
1.使用pthread_mutex_lock上锁
2.调用pthread_cond_wait
2.1将当前线程放入队列
2.2解锁
2.3休眠
2.4获取锁
2.5休眠状态退出
3.你的程序
4.使用pthread_mutex_unlock解锁
参数:
@cond:条件变量的地址
@mutex:互斥锁
返回值:成功返回0,失败返回非零
4.给休眠的线程发信号或者广播
int pthread_cond_signal(pthread_cond_t *cond);
功能:唤醒一个休眠的线程
参数:
@cond:条件变量的地址
返回值:成功返回0,失败返回非零
int pthread_cond_broadcast(pthread_cond_t *cond);
功能:唤醒所有休眠的线程
参数:
@cond:条件变量的地址
返回值:成功返回0,失败返回非零
5.销毁条件变量
int pthread_cond_destroy(pthread_cond_t *cond);
功能:销毁条件变量
参数:
@cond:条件变量的地址
返回值:成功返回0,失败返回非零
3.3.2唤醒一个休眠的线程
#include <head.h>
//1.定义条件变量
pthread_cond_t cond;
pthread_mutex_t mutex;
//生产者
void *task1(void *arg)
{
int num = 5;
while (num--)
{
sleep(3);
printf("我生产了一辆小鹏汽车\n");
pthread_cond_signal(&cond);
}
pthread_exit(NULL);
}
//消费者
void *task2(void *arg)
{
int num = 5;
while (num--)
{
pthread_cond_wait(&cond,&mutex);
printf("我购买了一辆小鹏汽车\n");
}
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
pthread_t tid1, tid2;
//2.初始化条件变量
pthread_cond_init(&cond,NULL);
if (pthread_create(&tid1, NULL, task1, NULL))
PRINT_ERR("create tid1 error");
if (pthread_create(&tid2, NULL, task2, NULL))
PRINT_ERR("create tid1 error");
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
//5.销毁条件变量
pthread_cond_destroy(&cond);
return 0;
}
3.3.3唤醒多个休眠的线程
#include <head.h>
// 1.定义条件变量
pthread_cond_t cond;
pthread_mutex_t mutex;
//生产者
void *task1(void *arg)
{
// int num = 5;
// while (--num)
// {
// sleep(3);
// printf("我生产了1辆小鹏汽车\n");
// pthread_cond_signal(&cond);
// }
sleep(2);
printf("我生产了4辆小鹏汽车\n");
pthread_cond_broadcast(&cond);
pthread_exit(NULL);
}
//消费者
void *task2(void *arg)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
printf("tid = %#lx 购买了一辆小鹏汽车\n",pthread_self());
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
pthread_t tid1, tid2, tid3, tid4, tid5;
// 2.初始化条件变量
pthread_cond_init(&cond, NULL);
pthread_mutex_init(&mutex, NULL);
if (pthread_create(&tid1, NULL, task1, NULL))
PRINT_ERR("create tid1 error");
if (pthread_create(&tid2, NULL, task2, NULL))
PRINT_ERR("create tid1 error");
if (pthread_create(&tid3, NULL, task2, NULL))
PRINT_ERR("create tid1 error");
if (pthread_create(&tid4, NULL, task2, NULL))
PRINT_ERR("create tid1 error");
if (pthread_create(&tid5, NULL, task2, NULL))
PRINT_ERR("create tid1 error");
printf("tid2=%#lx,tid3=%#lx,tid4=%#lx,tid5=%#lx\n",
tid2,tid3,tid4,tid5);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);
pthread_join(tid4, NULL);
pthread_join(tid5, NULL);
// 5.销毁条件变量
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
3.3.4条件变量的使用场景
比如要编写一个12306购票的服务器,如果用户登录12306的客户端,服务器感知到之后客户端到来的时候创建一个线程服务于用户。但是如果在同一时刻内有很多用户同时登录买票的服务器,在这个时间点内就需要创建大量的线程,这些线程在创建的时候需要大量的时间。用户就会感觉到这个服务器特别的慢。一般我们会采用在服务器启动的时候创建一堆线程,让这些线程默认处于休眠pthread_cond_wait状态。当用户来的时候调用pthread_cond_signal唤醒休眠的线程,线程就可以直接服务于用户,这样可以大量节省创建线程的时间。所以上述的过程就可以通过条件变量完成。
作业:
1.使用两个线程拷贝同一个文件
1.1多线程拷贝同一个文件
#include <head.h>
typedef struct{
const char * src;
const char * dest;
int start;
int len;
}info_t;
int get_src_file_len(const char *srcfile,const char * destfile)
{
int sfd,dfd;
int len=0;
if((sfd = open(srcfile,O_RDONLY))==-1){
PRINT_ERR("open srcfile error");
}
if((dfd = open(destfile,O_RDWR|O_CREAT|O_TRUNC,0664))==-1){
PRINT_ERR("open destfile error");
}
len = lseek(sfd,0,SEEK_END);
close(sfd);
close(dfd);
return len;
}
int copy_file(const char *srcfile,const char * destfile,int start,int len)
{
int sfd,dfd;
char buf[10] = {0};
int ret=0,count=0;
if((sfd = open(srcfile,O_RDONLY))==-1){
PRINT_ERR("open srcfile error");
}
if((dfd = open(destfile,O_RDWR))==-1){
PRINT_ERR("open destfile error");
}
lseek(sfd,start,SEEK_SET);
lseek(dfd,start,SEEK_SET);
while(1){
ret = read(sfd,buf,sizeof(buf));
count+=ret;
if(ret==0 || count>len) {
write(dfd,buf,ret-(count-len));
break;
}
write(dfd,buf,ret);
}
close(sfd);
close(dfd);
return 0;
}
void *task(void *arg)
{
info_t f = *(info_t *)arg;
copy_file(f.src,f.dest,f.start,f.len);
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
pthread_t tid1, tid2;
int len;
if(argc != 3){
fprintf(stderr,"input error,try again\n");
fprintf(stderr,"usage:./a.out srcfile,destfile\n");
exit(EXIT_FAILURE);
}
len = get_src_file_len(argv[1],argv[2]);
info_t f[] = {
{argv[1],argv[2],0,len/2},
{argv[1],argv[2],len/2,(len-len/2)},
};
if (pthread_create(&tid1, NULL, task, (void *)&f[0]))
PRINT_ERR("thread 1 create error");
if (pthread_create(&tid2, NULL, task, (void *)&f[1]))
PRINT_ERR("thread 2 create error");
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}