Linux系统编程---进程相关接口介绍
简述
前面描述了Linux下进程的创建过程,在Linux下,我们可以用fork()来开创一个进程空间和父进程搭配执行,但在实际开发中,仍旧多用线程的方法去实现。关于线程与进程间的不同,我们可以通过上面这个该篇博文了解进程和线程关系及区别
相关接口
线程创建
#include<pthread.h>
int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr, void *(*start_rin)(void*),void **restrct arg);
//返回值:若成功,返回0,否则,返回值错误编号
- tidp:线程指向的一片内存单元
- attr :参数用于定制不同的线程属性,一般使用设置为NULL为默认属性
- start_in:函数地址
- arg:参数(如果传递的参数变量不止一个,那么可以使用一个结构体来包含这些变量)
#include<pthread.h>
#include<iostream>
#include<sys/types.h>
#include<unistd.h>
void *test_pthread(void *arg){
pid_t pid;
pid = getpid();
std::cout<<"second test_pthread"<<std::endl;
return NULL;
}
int main(){
pthread_t tpid;
int err=0;
std::cout<<"first thread "<<std::endl;
err = pthread_create(&tpid,NULL,&test_pthread,NULL);
if(err<0){
perror("thread create erro:");
exit(1);
}
pthread_join(tpid,NULL);
return 0;
}
wlm@wlm:~/code/example/Linux$ ./thread
first thread
second test_pthread
关于线程使用上,要注意一些问题,
- 开辟多个线程,用户是无法掌握线程的执行顺序,线程的执行是交给内核去处理调度的。
- 新创建的线程可以访问进程的地址空间,并且继承调用线程的浮点环境和信号屏蔽字,该信号挂起信号集会被清除。
线程终止
调用该接口,退出当前线程
- pthread_exit
pthread_exit
#include<pthread.h>
void pthread_exit(void *rval_ptr);
调用该接口,退出当前线程
- rval_ptr:如果线程是结合态,调用pthread_exit后,会将rval_ptr返回到主线程中
- pthread_join
#Include<pthread.h>
int pthread_join(pthread_t thread,void **rval_ptr);
- pthread_join调用后,会阻塞等待到对应的子线程退出。一文读懂线程的分离状态
- phtread_join使用涉及到一个线程状态的问题,主线程在创建子线程后,子线程的分离属性默认是结合态的,那么子线程执行结束后的资源释放问题是要交给主线程去释放的,主线程调用pthread_join后,则会阻塞等待子线程执行结束,释放其资源。在Linux中也提供了一个接口pthread_detech,将线程属性设置为分离状态,设置为分离态后,当线程退出后,系统就会将资源进行一个释放。
- pthread_cancel(pthread_t tid);
#Include<pthread.h>
int pthread_cancel(pthread_t tid);
//成功返回0,否则返回错误编号
通过调用该接口,来指定要“退出”的线程,这个接口会想指定线程发送退出信号,但是这是一个提醒,接收到该信号的线程可以选择拒绝(涉及线程间的信号控制)。
#include<pthread.h>
#include<iostream>
#include<sys/types.h>
#include<unistd.h>
void *test_pthread(void *arg){
pid_t pid;
pid = getpid();
std::cout<<"second test_pthread"<<std::endl;
int num=0;
while(true){
if(num == 12){
std::cout<<"pthread_cancel"<<std::endl;
//pthread_testcancel();
}
sleep(1);
std::cout<<"second:"<<num++<<std::endl;
}
std::cout<<"second 退出"<<std::endl;
return NULL;
}
int main(){
pthread_t tpid;
int err=0;
std::cout<<"first thread "<<std::endl;
err = pthread_create(&tpid,NULL,&test_pthread,NULL);
if(err<0){
perror("thread create erro:");
exit(1);
}
int i=0;
while(i<5){
std::cout<<"first"<<i++<<std::endl;
}
std::cout<<"取消线程"<<std::endl;
sleep(5);
pthread_cancel(tpid);
std::cout<<"join"<<std::endl;
pthread_join(tpid,NULL);
std::cout<<"成功退出"<<std::endl;
return 0;
}
first thread
first0
first1
first2
first3
first4
取消线程
second test_pthread
second:0
second:1
second:2
second:3
join
成功退出
这里测试的结果,发送取消信号后,子线程退出。pthread_cancel会提醒指定线程-“你可以退出了”,但退出的时机,则需要在下一次的系统调用(退出态),但是有时候,调用pthread_cancel并不会立即将线程取消,如果有遇到,可以看linux下pthread_cancel无法取消线程的原因
学习了Linux中线程的基本使用,可以发现进程与线程之间可以执行的任务其实多相似,只是二者在操作系统中所处地位不同,我们可以对进程和线程使用的接口进行一个比较
进程接口 | 线程接口 | 描述 |
---|---|---|
fork | pthread_create | 创建新的控制流 |
exit | pthread_exit | 从现有控制流中退出 |
waitpid | pthread_join | 从控制流中得到退出状态 |
getpid | pthread_self | 获取控制流ID |
abort | pthread_cancel | 请求控制流的非正常退出 |