linux 进程组和会话和线程

进程组和会话和线程

创建会话

6点注意事项

  • 调用进程不能是进程组的组长, 该进程会变成新会话的首进程
  • 该进程成为一个新进程的组长进程
  • 需要有root权限
  • 新会话丢弃原有的控制终端, 该会话无控制终端, 即无法与用户交互
  • 若调用进程是组长进程, 则会出错返回
  • 建立新会话时, 先调用fork, 父进程终止, 子进程调用setsid
getsid函数
作用: 查看当前进程在的会话的id
pid_t getsid(pid_t pid);
参数:
	pid: 要查看的进程的pid
		0 : 本组的会话id
返回值:
	成功: 当前的会话id
	失败: -1, 设置errno
setsid函数
作用: 当当前进程不是组的组长时, 则创建一个新的会话, 然后使其成为会话组长和组组长
pid_t setsid(void);
返回值:
	成功: 返回调用的进程的会话ID
	失败: -1, 设置errno

守护进程

​ 是linux中后台服务进程, 通常独立于控制终端, 并且周期性的执行某种任务或等待处理某些发生的事情, 一般采用以d结尾的名字

守护进程的特点:

  • 没有控制终端
  • 不能和用户直接交互
  • 不受用户的登陆,注销的影响
  • 始终运行
创建守护进程模型
  1. 创建子进程, 父进程退出

  2. 在子进程中创建新会话

    setsid()

  3. 改变当前目录位置

    chdir()

  4. 重设文件权限掩码

    umask()

    防止继承的文件创建屏蔽字拒绝某些权限

  5. 关闭/重定向文件描述符

    因为继承打开的文件不会用到, 浪费系统资源, 无法卸载

    重定向: 将之前的文件重定向到/dev/null

  6. 开始执行守护进程核心工作, 守护进程退出处理程序模型

    while()

chdir函数
作用: 改变当前工作目录的位置, 防止占用可卸载文件系统
int chdir(const char *path);
参数:
	path: 目标目录的路径
返回值:
	成功: 0
	失败: -1, 设置errno
umask函数
作用: 
mode_t umask(mode_t mask);
参数:
	mask: 8进制的值

返回值:
	成功: 之前设置的值

线程的概念

线程是轻量级进程

进程和线程的区别:

  • 进程有独立的地址空间,有独立的pcb
  • 线程无独立的地址空间,有独立的pcb

在linux中, 线程是最小的执行单元, 进程是最小的资源分配单元

查看pid程序的线程

ps -Lf <pid>
liux内核实现原理
  • 创建线程使用的底层函数与进程一样clone
  • 从内核看, 进程和线程一样, 都有自己的不同的pcb, 但是pcb中指向内存资源的三级页表是相同的
  • 进程可以蜕变成线程
  • 线程是最小的执行单元, 进程是最小的资源分配单元
线程共享的资源
  1. 文件描述符

  2. 每种信号的处理方式

    信号处理方式: 哪个线程抢到了,哪个线程就处理他

  3. 当前工作目录

  4. 用户id和组id

  5. 内存地址空间

    (.text/ .data/ .bss/ 共享库)

线程非共享资源
  1. 线程id

  2. 处理器现场和栈指针(内核栈)

  3. 独立的栈空间(用户栈空间)

  4. errno变量(全局变量)

  5. 信号屏蔽字

    可以指定某一个线程来处理一个特定的信号

  6. 调度优先级

线程的优点/缺点

优点:

  1. 提高程序的并发性
  2. 开销小
  3. 数据通信,共享数据方便

缺点:

  1. 库函数, 不稳定
  2. 调试, 编写困难
  3. 对信号支持不好

线程控制原语

检查出错返回值

不能使用perror()!!

fprintf(stderr, "xxx error: %s\n", strerror(ret));
pthread_self函数
作用:获取线程id
pthread_t pthread_self(void);
返回值:
	当前线程的id
pthread_create函数
作用:创建一个新进程
int pthread_create(pthread_t *restrict thread,
                   const pthread_attr_t *restrict attr,
                   void *(*start_routine)(void *),
                   void *restrict arg);
参数:
	thread: 传出参数, 新创建线程的线程id
	attr: 线程属性, 默认为NULL
	start_routine: 子线程回调函数, 创建成功, pthread_create函数返回时,该函数会被自动调用
	arg: start_routine的参数, 若没有,则为NULL
    
返回值:
	成功: 0
	失败: 错误号, 且thread为定义
pthread_exit函数
作用: 退出当前的线程(包括主线程)
noreturn void pthread_exit(void *retval);
参数:
	retval: 推出值, 无推出值时, NULL
返回值:
	无

比较:

  • exit()退出当前进程
  • return返回到调用者
  • pthread_exit()推出当前线程
pthread_join函数
作用:阻塞地回收指定的线程, 并且可以获取等待线程的返回值
int pthread_join(pthread_t thread, void **retval);
参数:
	thread:传入参数, 待回收的线程id
	reval: 传出参数, 为待回收的线程的退出值
			若线程异常结束, 值为-1
返回值:
	成功: 0
	失败: 错误号
pthread_cancel函数
作用:杀死线程, 需要一个取消点(保存点)
int pthread_cancel(pthread_t thread);
参数:
	thread: 待杀死的线程id
	返回值:
		成功: 0
		失败: 错误号

注意:

  • 如果子线程没有到达取消点, 则pthread_cancel无效,此时可以手动添加取消点 pthread_testcancel()
  • 成功被pthread_cancel()杀死的线程, 返回-1, 使用pthread_join来回收该值
pthread_detach函数
作用: 将指定的线程分离
int pthread_detach(pthread_t thread);
参数:
	thread: 待分离的线程id
返回值:
	成功: 0
	失败: 错误号

分离了以后,当线程终止的时候,线程会自己回收自己的pcb, 无需主线程用join来回收


线程控制原语进程控制原语
pthread_createfork
pthread_selfgetpid
pthread_exitexit
pthread_joinwait/waitpid
pthread_cancelkill
pthread_detach

线程属性

typedef struct
{
       int 					__detachstate;		// 线程的分离状态
       int 					__schedpolicy;		// 线程的调度策略
       struct sched_param 	__schedparam;		// 线程的调度参数
       int 					__inheritsched;		// 线程的继承性
       int 					__scope;			// 线程的作用域
       size_t 				__guardsize;		// 线程的缓冲区大小
       int 					__stackaddr_set;	// 线程的栈设置
       void* 				__stackaddr;		// 线程的栈位置
       size_t 				__stacksize;		// 线程的栈大小
} pthread_attr_t;
线程属性初始化

注意: 应该先初始化线程属性, 再pthread_create创建线程

作用:初始化线程属性
int pthread_attr_init(pthread_attr_t *attr);
参数:
	attr: 传出参数, 初始化以后的属性
返回值:
	成功: 0
	失败: 错误号


作用: 销毁线程属性所占用的资源
int pthread_attr_destroy(pthread_attr_t *attr);
参数:
	attr: 待销毁的线程属性
返回值:
	成功: 0
	失败: 错误号
设置线程分离
作用:设置当前线程分离的属性
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
参数:
	attr: 传出参数, 待修改的属性值
	detachstate: 线程分离的属性值
		PTHREAD_CREATE_DETACHED(分离的)
		PTHREAD_CREATE_JOINABLE(未分离的,默认的)
返回值:
	成功: 0
	失败: 错误号
	
作用: 获取当前线程分离的属性
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
参数:
	attr: 已初始化的线程属性
	detachstate: 传出参数, 当前线程的状态
返回值:	
	成功: 0
	失败: 错误号
实例
通过线程属性将一个线程设置为分离态
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, tfn, NULL);
pthread_attr_destroy(&attr);

线程使用注意事项

  • 主线程退出, 其他线程推出, 则用pthread_exit
  • 避免僵尸线程
    • pthread_join
    • pthread_detach
    • pthread_create, 指定分离属性
  • mallocmmap申请的内存可被其他的线程释放
  • 避免在多线程中调用fork, 除非马上exec .子进程中只有fork线程存在, 其他的进程均要pthread_exit(即,只存活了调用fork的进程)
  • 信号和多线程不要同时用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值