注意:pthread的返回值
成功:几乎全是返回0
失败:返回非0
1.查看线程ID
1.找到程序的进程ID:ps aux | grep 程序名
2.ps -Lf 进程ID:LWP
2.pthread_create
int pthread_create(
pthread_t *thread, //传出参数:线程ID=unsigned long
const pthread_attr_t *attr, //线程属性,NULL
void *(*start_routine) (void *), //线程回调函数
void *arg //线程回调函数的参数
);
返回值:
成功返回0,失败返回错误号
perror()不能使用该函数打印错误信息,而是使用strerror(ret),打印错误码
注意:主线程先退出,子线程会被强制结束
程序案例*
重点:int和void*之间的强制转换----->(直接强制转换即可)
void* myfunc(void* arg){
printf("%dth child thread id = %lu\n",(int)arg,pthread_self());
//printf("%dth child thread id = %lu\n",*(int*)arg,pthread_self());
for(int i=0;i<5;i++){
if(i==(int)arg)
pthread_exit(NULL); //return NULL;
}
return NULL;
}
int main(){
pthread_t tid[5];
int i;
for(i=0;i<5;i++){
int ret=pthread_create(&tid[i],NULL,myfunc,(void*)i);
//pthread_create(&tid[i],NULL,myfunc,(void*)(&i));
if(ret!=0){ //pthread_create的返回值
printf("error number : %d\n",ret); //打印错误码
printf("%s\n",strerror(ret)); //strerror(ret)
}
}
printf("parent thread id = %lu\n",pthread_self());
sleep(1);
}
3.pthread_exit
void pthread_exit(void *retval);
retval:当线程函数中,执行pthread_exit退出后,retval参数被主线程pthread_join函数
的第二个参数接收到。
4.pthread_join 阻塞等待线程退出,回收TCB,获取线程退出状态
int pthread_join(pthread_t thread, void **retval);
作用:使主线程等待线程ID=thread子线程执行完后,才退出;[获取子线程的返回值]
thread:要回收的子线程的线程ID
retval:(传出参数)读取线程退出的时候携带的状态信息
void* ptr;
pthread_join(tid,&ptr);
指向的内存和pthread_exit的参数指向同一块内存地址
案例:pthread_exit和return:返回线程函数中的值
struct node{
int data;
char buf[1024];
};
void* thread_func(void* arg){
struct node* nd=(struct node*)malloc(sizeof(struct node));
nd->data=100;
strcpy(nd->buf,"Thunder");
//pthread_exit(nd); //方法1
return nd; //方法2
}
int main(){
pthread_t tid;
int ret=pthread_create(&tid,NULL,thread_func,NULL);
if(ret!=0)
printf("ret=%d,error=%s\n",ret,strerror(ret));
void* retval=NULL;
pthread_join(tid,&retval);
printf("%d,%s\n",((struct node*)retval)->data,((struct node*)retval)->buf);
}
代码分析:
线程函数:pthread_exit(nd); return(nd);
struct node* nd=(struct node*)malloc(sizeof(struct node));
nd->data=100;
strcpy(nd->buf,"Thunder");
//pthread_exit(nd); //方法1
return nd; //方法2
主线程中:pthread_join获取retval
void* retval=NULL;
pthread_join(tid,&retval); //retval指针指向nd
printf("%d,%s\n",((struct node*)retval)->data,((struct node*)retval)->buf);
5.pthread_detach 线程分离
1.默认创建的线程,是不分离的,可能会产生僵尸线程,如何解决?
1.在主线程中调用pthread_join函数,等待子线程全部执行完毕后,主线程才退出
2.子线程中调用pthread_detach函数,使得子线程从主线程中分离,子线程的资源由系统回收
2.如何使线程分离?
[1]在子线程中调用pthread_detach函数
int pthread_detach(pthread_t thread);
[2]在创建线程之前,设置线程属性为[分离]
pthread_attr_t attr; //线程属性类型
int pthread_attr_init(pthread_attr_t *attr); //初始化
int pthread_attr_destroy(pthread_attr_t *attr); //释放
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate); //[获取]attr的分离状态
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); //[设置]attr的分离状态
attr:线程属性
detachstate:
PTHREAD_CREATE_DETACHED (分离)
PTHREAD_CREATE_JOINABLE (不分离)
[案例]:
pthread_attr_t attr; //定义线程属性变量
pthread_attr_init(&attr); //初始化线程属性变量
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); //设置attr为线程可分离
pthread_create(&tid,&attr,pthread_func,NULL); //创建线程时,使用attr参数
pthread_attr_destroy(&attr); //最终不要忘记,释放attr
6.pthread_cancel 杀死(取消)线程
int pthread_cancel(pthread_t thread);
1.作用:在主线程中,取消线程ID=thread的线程
2.注意事项:要杀死的子线程的线程处理函数内部,必须做过一次[系统调用]。换句话说,取消点必
须是[系统调用],如果被取消的线程没有系统调用,则该线程不能被取消。
3.pthread_testcancel(); //设置一个取消点
如果线程的处理函数中确实没有[系统函数],可以调用pthread_testcancel()函数设置一个取消点,使得
该子线程能够被pthread_cancel函数取消。
7.pthread_equal 判断两个线程的ID是否相等
int pthread_equal(pthread_t t1, pthread_t t2);