线程控制
线程控制分为:线程创建-》线程终止-》线程等待-》线程分离
我们首先来说说线程创建:
线程创建
Linux下线程是用户级线程,所以系统并没有给我们提供相关接口。线程控制当中我们使用的是库函数。(由此也可以验证在内核中是没有线程这个概念的。)
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void*(*start_routine)(void*),void *arg);
1.thread:线程标识符,类型是pthread_t,是线程空间的首地址,通过这个标识符可以对当前线程进行操作,是一个出参。
2.attr: pthread_attr_t是一个结构体,设置线程的属性,一般设置为NULL,表示默认属性。
3.start_routine:是线程入口函数地址,线程启动后执行的函数。
4.arg:入口函数的参数,可以传自定类型。
5.返回值:成功返回0,是被返回错误码。
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
void* thread_start(void* arg)
{
while(1)
{
printf("i am %s\n",(char*)arg);
sleep(2);
}
return NULL;
}
int main()
{
pthread_t thread;
int ret;
ret=pthread_create(&thread,NULL,thread_start,"thread");
while(1)
{
printf("i am main \n");
sleep(1);
}
return 0;
}
pthread_create函数产生了一个线程id,存放在第一个参数指向的地址中,该线程id是指用户级线程id。 因此线程库提供了相关接口,可以用来获得线程自身的id。
pthread_t pthread_self(void);//获得线程自己的id。
线程的终止
线程的终止方式:
1.从线程入口函数的return返回。
2.void pthread_exit(void* retval) ;
调用此函数也可以退出线程。
(1) retval为当前线程退出的信息,也可以传入NULL。
(2)当在主线程调用这个函数时,进程不会退出。但是主线程会进入ZI+状态。也就是变成了一个“僵尸进程”,工作线程状态为Sl+。
3.int pthread_cancel(pthread_t thread);
此函数可以结束任一线程,任一执行流。
注意:
创建线程的时候,如果是默认属性创建的。那么当线程退出的时候,需要被别人来回收退出线程所使用的资源,否则在共享区中的该线程的资源不会被释放,也就是会造成内存泄漏。(默认属性为joinable)
线程等待
我们先来想想线程为什么要等待?
因为线程退出之后,其资源还没有被释放,如果不等待回收就会造成内存泄漏。类似于进程里的僵尸进程,但是因为线程没有父子概念,都是对等的,所以不能说为僵尸进程。总而言之线程等待是为了释放退出线程的资源,防止内存泄漏。
接口函数:pthread_join(pthread_t thread,void **retval);
功能:阻塞等待线程退出,回收资源。
thread:线程id
retval:指向一个指针,线程函数的返回值。是一个出参。
因为线程终止有三种情况,所以线程等待也有对应的三种情况:
1.若是从线程入口函数的return返回的,则使用pthread_join函数获取入口函数的返回值。
2.若线程是调用pthread_exit(void*)终止的。则可以使用pthread_join函数获取void*的值。
3.若线程是被pthread_cancel终止的,则pthread_join获取的值是一个常量PTHREAD_CANCELED。
线程分离
线程为什么要分离?
线程退出的时候,由于默认属性是joinable属性,资源需要被其他线程释放。为了解决这种情况,可以将线程设置为线程分离,这样当线程结束的时候,不需要别人来释放资源了,操作系统直接回收掉了。
接口函数:int pthread_detach(pthread_t thread);
功能:给线程设置分离属性。