线程的概念
线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含多个线程,这些线程共享进程的资源,如内存空间和文件描述符,但每个线程有自己的栈和寄存器状态。
进程和线程的异同
相同点:
都为系统提供并发执行的能力
不同点:
资源和调度:进程是系统资源分配的最小单位,线程是资源调度的最小单位
地址空间:每个进程都有独立的地址空间;同一个进程中的多个线程共享进程地址空间
通信方面:多线程的通信比较简单,借助全局变量,但是需要考虑临界资源的访问问题;多进程的通信比较复杂,需要借助3-4g的内核空间(共享的)来完成通信
安全性方面:进程相对比较安全(空间独立,一个进程退出不会影响其他进程),线程安全性相对较低,进程退出其中的线程会随之结束
创建和销毁:创建和销毁线程比进程要快,因为系统只需要为线程分配必要的资源,而进程需要分配完整的资源。
相关函数
创建线程
pthread_create()
定义:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
功能:
创建线程,并将线程的控制块存储在thread中。
参数:
thread:指向线程ID的指针,用于存储创建的线程的ID。
attr:线程属性,用于设置线程的属性,可以为NULL。
start_routine:线程的入口函数,线程执行时调用该函数。
arg:传递给线程的入口函数的参数。
返回值:
0:成功创建线程。
EINVAL:attr参数不合法。
EAGAIN:资源不足,无法创建线程。
ENOMEM:内存不足,无法创建线程。
注意:该函数属于第三方库函数,编译时需要手动链接。
gcc xx.c -lpthread
结束线程
pthread_exit()
定义:
void pthread_exit(void *retval);
功能:
结束线程的执行,释放线程的所有资源,并将线程的返回值设置为retval。
参数:
retval:线程的返回值。
注意:该函数不返回,只能在线程的入口函数中调用。
等待(回收)线程
pthread_join()
定义:
int pthread_join(pthread_t thread, void **retval);
功能:
等待线程thread执行完毕,并获取线程的返回值。
参数:
thread:等待的线程ID。
retval:指向线程的返回值的指针,用于存储线程的返回值。
返回值:
0:成功获取线程的返回值。
EINVAL:thread参数不合法。
ESRCH:线程thread不存在。
EDEADLK:线程自身或其父线程正在等待。
获取线程ID
pthread_self()
定义:
pthread_t pthread_self(void);
功能:
获取当前线程的ID。
返回值:
当前线程的ID。
线程分离
pthread_detach()
定义:
int pthread_detach(pthread_t thread);
功能:
将线程thread从父进程中分离,使得线程在完成后不受父进程控制。
参数:
thread:分离的线程ID。
返回值:
0:成功分离线程。
EINVAL:thread参数不合法。
ESRCH:线程thread不存在。
使用线程分离函数可以保证子线程结束时,系统能够自动回收资源,不需要再调用pthread_join()函数来回收资源,同时也避免了僵尸线程的产生。
使用方式:
1.在主线程中调用pthread_detach(tid);
2.在子线程中调用pthread_detach(pthread_self());
注意:
1.如果线程已经设置了分离状态,则再调用pthread_join就会失败
2.pthread_datach 和 pthread_join 如何选择?
1)当主线程中希望有阻塞操作时,可以选择调用pthread_join函数回收线程
2)当主线程本身有循环操作,希望子线程在结束时立马回收线程可以选择pthread_detach设置分离属性
3.设置线程的分离属性有两种方式:
1)通过pthread_detach进行设置
2)通过pthread_create函数的第二个参数(线程属性)来设置分离属性
取消线程
pthread_cancel()
定义:
int pthread_cancel(pthread_t thread);
功能:
取消线程thread的执行。
参数:
thread:要取消的线程ID。
返回值:
0:成功取消线程。
ESRCH:线程thread不存在。
EINVAL:thread参数不合法。
EDEADLK:线程自身或其父线程正在等待。