IO Day5
- 线程
- 相关函数
- `pthread_create`
- `pthread_self`
- `pthread_exit`
- `pthread_join\pthread_detach`
- `pthread_cancel`
- `pthread_setcancelstate`
- `pthread_setcanceltype`
- 作业
线程
- 线程是轻量化的进程,一个进程内可以有多个线程,至少包含一个线程(主线程)。
- 线程的任务调度,创建,销毁的开销都要比进程小。
- 进程之间不共享资源,进程运行空间都是独立的,但是线程共享临界资源。
- 线程是任务调度的最小单位,进程是资源分配的最小单位。
- 多任务并发执行大多数选择多线程,而不是多进程,因为线程占用内存非常少大概8K。
- 多个线程每一个都有自己的id号。
- 线程函数来自于第三方库,-pthread,所以要编译线程库函数需要加上 -pthread
- 多线程编程时,对于临界资源访问时可能有多个线程同时访问,这样会产生数据的错乱,这种现象被称为竞态。
- 临界资源:全局变量,临界区:访问临界资源的代码。
相关函数
pthread_create
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, *(*start_routine) (void *), void *arg);
功能:创建子线程的函数
参数1:存储创建的子线程号
参数2:创建时附加的线程属性,默认填NULL
参数3:函数指针,子线程的线程体函数,也是子线程开始运行的地方。
参数4:是线程体函数的参数,如果没有参数填NULL即可。
返回值:成功返回0,失败返回-1,并且线程号不确定。
pthread_self
#include <pthread.h>
pthread_t pthread_self(void);
功能:获取调用线程的线程号
参数:无
返回值:返回调用线程的线程号。
pthread_exit
#include <pthread.h>
void pthread_exit(void *retval);
功能:退出调用线程
参数:任意类型的变量,存储检索后的内容。
返回值:无
pthread_join\pthread_detach
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
功能:阻塞回收子线程的资源。
参数1:要退出的线程号
参数2:线程退出时的状态,一般不接收填NULL。
返回值:成功返回0,失败返回一个错误码。
#include <pthread.h>
int pthread_detach(pthread_t thread);
功能:非阻塞将线程设置为分离态,设置为分离态的线程由系统回收资源。
参数:要设置为分离态的线程号
返回值:成功返回0,失败返回一个错误码。
pthread_cancel
#include <pthread.h>
int pthread_cancel(pthread_t thread);
功能:向线程发送取消信号。
参数:线程号
返回值:成功返回0,失败返回非0错误码。
pthread_setcancelstate
#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
功能:设置调用线程是否可被取消
参数1:
PTHREAD_CANCEL_ENABLE:默认线程可被取消
PTHREAD_CANCEL_DISABLE:线程不可被取消
参数2:线程原始的状态。
返回值:成功返回0,失败返回非0错误码。
pthread_setcanceltype
#include <pthread.h>
int pthread_setcanceltype(int type, int *oldtype);
功能:设置线程延迟取消。
参数1:
PTHREAD_CANCEL_DEFERRED:默认延迟取消
PTHREAD_CANCEL_ASYNCHRONOUS:不延迟,立刻取消。
参数2:线程原始的类型。
返回值:成功返回0,失败返回非0错误码。
作业
多线程实现文件拷贝,线程1拷贝一半,线程2拷贝另一半,主线程回收子线程资源
#include <myhead.h>
void *fun1(void *len)
{
int fd1, fd2;
fd1 = open("./1.txt", O_RDONLY); //只读打开文件1
if (fd1 == -1)
{
perror("open");
pthread_exit(NULL);
}
fd2 = open("./2.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664); //只写打开文件2
if (fd2 == -1)
{
perror("open");
pthread_exit(NULL);
}
char buff[100]; //存储数据
int sum = 0; //写入计数
while (1)
{
int res = read(fd1, buff, sizeof(buff)); //读取数据
sum += res; //计数累加
if (res == 0 || sum > *(int *)len/2) //读取结束或者超过一半
{
write(fd2, buff, res - (sum - *(int *)len/2)); //写入未超过一半的剩余数据
break;
}
write(fd2, buff, res); //正常写入数据
}
close(fd1); //关闭文件描述符
close(fd2);
pthread_exit(NULL);
}
void *fun2(void *len)
{
sleep(1); //防止线程产生竞态
int fd1, fd2;
fd1 = open("./1.txt", O_RDONLY); //只读打开文件1
if (fd1 == -1)
{
perror("open");
pthread_exit(NULL);
}
fd2 = open("./2.txt", O_WRONLY | O_CREAT, 0664); //只写打开文件2
if (fd2 == -1)
{
perror("open");
pthread_exit(NULL);
}
lseek(fd1, *(int *)len/2, SEEK_SET);
lseek(fd2, *(int *)len/2, SEEK_SET);
char buff[100]; //存储数据
int sum = 0; //写入计数
while (1)
{
int res = read(fd1, buff, sizeof(buff)); //读取数据
sum += res; //计数累加
if (res == 0 || sum > *(int *)len/2) //读取结束或者超过一半
{
write(fd2, buff, res - (sum - *(int *)len/2)); //写入未超过一半的剩余数据
printf("1");
break;
}
write(fd2, buff, res); //正常写入数据
}
close(fd1); //关闭文件描述符
close(fd2);
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
pthread_t tid1, tid2; //定义线程
int fd1 = open("./1.txt", O_RDONLY); //计算待处理文件长度
if (fd1 == -1)
{
perror("open");
return -1;
}
int len = lseek(fd1, 0, SEEK_END);
close(fd1);
if (pthread_create(&tid1, NULL, fun1, &len)) //创建子线程1
{
perror("pthread_create");
return -1;
}
if (pthread_create(&tid2, NULL, fun2, &len)) //创建子线程2
{
perror("pthread_create");
return -1;
}
pthread_join(tid1, NULL); //回收线程
pthread_join(tid2, NULL);
return 0;
}
运行结果