8- 线程

1. 基本概念

1.1 概述

  1. 线程(LWP)再Linux系统下,本质也是进程,即从内核的角度看,进程与线程无区别。
  2. 进程时操作系统分配资源的最小单位,线程时操作系统调度执行的最小单位。
    (1)因此父子进程拥有不同的虚拟地址空间,但父子线程却共享一个虚拟地址空间;
    (2)由于从内核的角度看无区别,因此线程同进程一样会争抢cpu资源。
  3. 线程创建共享虚拟内存,但会复制一份tcp(线程管理块);
  4. 查看线程命令:ps -Lf -->LWP
  5. 线程之间的资源共享:除了栈和阻塞信号集不共享,虚拟地址空间都共享。

1.2 创建线程

创建出子线程pthread, 并将arg作为参数传入start_routine函数作为pthread的运行逻辑
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
attr:线程属性,一般是NULL;
返回值:成功返回0;失败返回error值
注意:此处error与errno属于不同库,因此需要通过strerror()函数打印;
返回当前进程tid;
pthread_t pthread_self(void);

注意:
(1)由于主线程和子线程使用同一个虚拟地址空间,所以当主线程执行完退出时会自动释放空间,影响子线程无法执行;但子线程执行完时退出时,并不会释放而影响主线程的运行。
(2)为了解决主线程退出影响子线程问题,可以采用pthread_exit()函数
(3)编译时gcc -lpthread

主线程执行完成退出前执行该函数,则不会释放空间,知道子线程执行结束
void pthread_exit(void *retval);
	retval, 线程退出时候的返回值

示例

//创建子线程
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>


void* callback(void *arg)
{
	printf("arg = %d\n", *((int *)arg));
	printf("tid = %ld\n", pthread_self());
	pthread_exit(NULL);
}

int main()
{
	//1.创建子线程
	pthread_t tid;
	int num = 100;
	int ret = pthread_create(&tid, NULL, callback, (void*)(&num));
		//1.1若创建失败
	if(ret != 0)
	{
		char* s = strerror(ret);
		exit(0);
	}
	//2.主线程执行逻辑
	for(int i = 0; i < 5; i++)
	{
		printf("%d\n", i);
	}
	printf("tid = %ld\n", tid);
	printf("tid_self = %ld\n", pthread_self());
	pthread_exit(NULL);
	return 0;
}

1.3 回收子线程资源

#include <pthread.h>
这是个阻塞函数, 调用一次回收一个子线程
这个函数在主线程(父线程)中使用
int pthread_join(pthread_t thread, void **retval);
参数:
- thread: 要回收的子线程的线程ID
- retval: 使用这个变量接收子线程退出的时候返回的值
//返回的数据
struct test
{
	char name[64];
	int age;
};
struct test t;	//不可以再callback函数内部定义
void* callback(void *arg)
{
	printf("arg = %d\n", *((int *)arg));
	printf("tid = %ld\n", pthread_self());
	t.age = 10;
	strcpy(t.name, "Li lei");
	pthread_exit(&t);
}

int main()
{
	//1.创建子线程
	pthread_t tid;
	int num = 100;
	int ret = pthread_create(&tid, NULL, callback, (void*)(&num));
		//1.1若创建失败
	if(ret != 0)
	{
		char* s = strerror(ret);
		exit(0);
	}
	//2.主线程执行逻辑
	for(int i = 0; i < 5; i++)
	{
		printf("%d\n", i);
	}
	printf("tid = %ld\n", tid);
	printf("tid_self = %ld\n", pthread_self());
	
	//3.获取子线程返回值
	struct test *ptr;
	pthread_join(tid, (void**)&ptr);
	printf("name = %s\n, age = %d\n", ptr->name, ptr->age);
	return 0;

}

注意:若子线程的返回值结构体的定义若再子线程里面,则无法正常的返回主线程;因为主线程与子线程不共享栈,而且pthread_exit()和pthread_join()函数是通过指针来传递返回值,因此当子线程结束时,栈释放了,主线程无法通过传递的指针参数找到子线程的返回值。

1.4 线程分离

将thread子线程从当前主线程分离
int pthread_detach(pthread_t thread);
	成功0,失败error号
  1. 子线程分离后,子线程的资源回收改由操作系统进行,而非主线程
  2. 但子线程依然使用主线程的虚拟内存空间,因此主线程需要pthread_exit();函数避免影响子线程;
  3. 但主线程的pthread_join()函数无法使用,否则会报错,因为其是回收子线程资源的函数。
int main()
{
	//1.创建子线程
	pthread_t tid;
	int num = 100;
	int ret = pthread_create(&tid, NULL, callback, (void*)(&num));
		//1.1若创建失败
	if(ret != 0)
	{
		char* s = strerror(ret);
		exit(0);
	}
		//1.2线程分离
	pthread_detach(tid);
	//2.主线程执行逻辑
	for(int i = 0; i < 5; i++)
	{
		printf("%d\n", i);
	}
	printf("tid = %ld\n", tid);
	printf("tid_self = %ld\n", pthread_self());
	pthread_exit(NULL);
	
	return 0;

}

1.5 线程取消

  1. 主线程可以调用pthread_cancel()函数终止子线程;
  2. 被终止的子线程并不会马上终止,而是在运行到从用户区向内核区切换的位置时终止。
  3. 如果没有取消点,则子线程并不会终止
将pthread子线程终止
int pthread_cancel(pthread_t pthread);
int main()
{
	//1.创建子线程
	pthread_t tid;
	int num = 100;
	int ret = pthread_create(&tid, NULL, callback, (void*)(&num));
		//1.1若创建失败
	if(ret != 0)
	{
		char* s = strerror(ret);
		exit(0);
	}
		//1.2线程分离
	pthread_detach(tid);
		//1.3线程取消
	pthread_cancel(tid);
	//2.主线程执行逻辑
	for(int i = 0; i < 5; i++)
	{
		printf("%d\n", i);
	}
	printf("tid = %ld\n", tid);
	printf("tid_self = %ld\n", pthread_self());
	pthread_exit(NULL);
	
	return 0;

}

1.6 线程属性

  1. 需要属性的变量 -> 对应一块内存
  2. 首先要申请一块内存, 并且初始化, 保存属性信息
  3. 当属性信息对应的变量使用完毕, 需要释放
// 线程属性类型
pthread_attr_t t;
// 初始化
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
// 释放资源
int pthread_attr_destroy(pthread_attr_t *attr);
// 通过设置属性实现线程分离
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
- detachstate:
PTHREAD_CREATE_DETACHED: 设置线程分离
PTHREAD_CREATE_JOINABLE: 设置父子线程不分离
int main()
{
	//1.创建子线程
	pthread_t tid;
	int num = 100;
	//1.1设置线程属性
	pthread_attr_t attr;//创建线程属性变量
	pthread_attr_init(&attr);//初始化变量
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//设置线程属性为线程分离
	int ret = pthread_create(&tid, &attr, callback, (void*)(&num));//将线程属性传入新建子线程
		//1.1若创建失败
	if(ret != 0)
	{
		char* s = strerror(ret);
		exit(0);
	}
		//1.2线程分离
	pthread_detach(tid);
		//1.3线程取消
	pthread_cancel(tid);
	//2.主线程执行逻辑
	for(int i = 0; i < 5; i++)
	{
		printf("%d\n", i);
	}
	printf("tid = %ld\n", tid);
	printf("tid_self = %ld\n", pthread_self());
	pthread_exit(NULL);
	//释放线程属性资源
	pthread_attr_destory(&attr);
	return 0;
}

1.7 文件属性函数

// 判断文件权限, 或者文件是否存在
int access(const char *pathname, int mode);
参数:
- pathname: 文件名
- mode:
R_OK: 判断文件是不是有读权限
W_OK: 判断文件是不是有写权限
X_OK: 判断文件是不是有执行权限
F_OK: 判断当前文件是否存在
返回值:
判断成功: 0, 失败: -1
     
// 修改文件权限
int chmod(const char *filename, int mode);
参数:
- filename: 要修改文件权限的文件的名字
- mod: 八进制数
// 修改文件所有者
int chown(const char *path, uid_t owner, gid_t group);
参数:
- path: 要修改的文件名
- owner: 用户ID, stat /etc/passwd
- group: 组ID   /etc/group
// 修改文件大小
int truncate(const char *path, off_t length);
参数:
- path: 要操作的文件
- length: 最终的文件大小

1.8 目录操作函数

// 文件重命名
int rename(const char *oldpath, const char *newpath);
参数:
- oldpath: 旧的文件名
- newpath: 新的文件名
// 修改进程的工作目录
// 在 /home/itcat启动a.out, a.out的工作目录 /home/itcast
// chdir("/") -> 进程切换到了根目录
int chdir(const char *path);
// == pwd命令
char *getcwd(char *buf, size_t size);
参数:
- buf: 存储路径, 指向一个由内存大小的数组
- size: 修饰buf大小
返回值:
指针指向一块内存, 这个内存就是第一个参数
// 创建目录
// 如果创建目录, 这个目录必须要有执行权限
int mkdir(const char *pathname, mode_t mode);
参数:
- pathname: 目录名
- mode: 目录的权限 mod & ~umask
// == rmdir命令, 只能删除空目录 rm -r
int rmdir(const char *pathname);
- pathname: 目录名
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值