一、pthread_cancel函数
pthread_cancel
函数用于请求取消一个线程。当调用 pthread_cancel
时,它会向指定的线程发送一个取消请求。
#include <pthread.h>int pthread_cancel(pthread_t thread);
thread
:要发送取消请求的线程标识符。
- 成功时,返回
0
。 - 失败时,返回一个错误号
二、pthread_detach函数
pthread_detach
用于将线程标记为“分离”状态。分离线程(detached thread)在完成执行后会自动释放其资源,主线程不需要调用 pthread_join
来回收这些资源。
#include <pthread.h>int pthread_detach(pthread_t thread);
thread
: 需要被分离的线程标识符。
- 成功时,
pthread_detach
返回0
。 - 失败时,返回一个错误号
分离线程会在执行结束后自动释放资源,无需其他线程调用
三、进程和线程的优缺点
进程
优点
-
隔离性强:
- 每个进程有独立的地址空间,进程间的内存是完全隔离的,这减少了一个进程崩溃或异常对其他进程的影响。
-
安全性高:
- 由于进程间内存隔离,一个进程无法直接访问或修改另一个进程的内存,提高了系统的安全性。
-
稳定性:
- 进程的独立性使得系统在处理错误或异常时更稳定,崩溃的进程不会直接影响其他进程。
-
适合复杂任务:
- 进程适用于需要完全独立执行的复杂任务,如不同的应用程序或服务。
缺点
-
创建和销毁开销大:
- 创建和销毁进程的开销较大,因为需要分配和管理独立的地址空间。
-
通信复杂:
- 进程间通信(IPC)较为复杂且性能开销较大。需要通过文件、管道、消息队列等方式来实现。
线程
优点
-
创建和销毁开销小:
- 线程创建和销毁的开销较小,因为线程共享同一进程的地址空间。
-
通信效率高:
- 线程之间的通信较为简单和高效,因为它们共享同一进程的地址空间,可以直接访问共享数据。
-
适合轻量级任务:
- 线程适用于需要并发执行的轻量级任务,如多线程的计算任务或I/O操作。
缺点
-
安全性较低:
- 由于线程共享进程的地址空间,一个线程的错误可能会影响到其他线程,增加了数据竞争和同步问题的风险。
-
同步复杂:
- 多线程程序需要处理线程间的同步和互斥,以避免竞争条件和数据不一致的问题,这增加了编程复杂性。
-
稳定性问题:
- 一个线程的崩溃或未处理的异常可能导致整个进程的崩溃,因为所有线程共享同一进程的资源和状态。
四、线程同步
线程中共享的资源称为临界资源,使用临界资源的部分代码称为临界区
1.互斥锁
用于保护共享资源,确保在同一时刻只有一个线程能够访问这些资源(排他性),它是一种软件层面上 的锁。
确保同一时间只有一个线程能够进入临界区(即访问共享资源的区域)。其他线程在进入临界区前必须等待直到互斥锁被释放。保证每个线程访问时的原子性操作。
初始化互斥锁
#include <pthread.h>int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
mutex
: 指向互斥锁的指针。attr
: 互斥锁的属性,通常为NULL
以使用默认属性
加锁
阻塞形式加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
阻塞调用线程直到成功获取锁。锁定后,其他线程尝试获取该锁将被阻塞。
尝试锁定互斥锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);
尝试获取锁,如果锁已被其他线程持有,则函数立即返回,而不是阻塞调用线程。
解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
解锁互斥锁,使其他等待的线程能够获取锁。
销毁锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
销毁互斥锁,释放其占用的资源。需要确保没有线程在使用该互斥锁时调用。
- 互斥锁引入了额外的性能开销过度使用互斥锁可能导致性能下降。
- 如果不正确地使用互斥锁(如多次锁定或解锁),可能会导致死锁,程序将无法继续执行。
五、死锁
死锁(Deadlock)是多线程或多进程编程中常见的一个问题,它指的是一组进程或线程在互相等待资源的过程中形成了一个循环依赖,导致它们都无法继续执行。简单来说,死锁是一种系统状态,在这种状态下,所有的进程或线程都在等待其他进程或线程释放资源,但由于互相等待,系统中的所有进程或线程都处于阻塞状态,无法继续执行。
死锁的形成有以下几个必要条件,只要其中任一条件不成立,死锁就不会发生:
1.互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁(如哲学家的筷子、打印机设备)。
像内存、扬声器这样可以同时让多个进程使用的资源是不会导致死锁的(因为进程不用阻塞等待
这种资源)。
2.不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。
3.请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放。
4.循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求。
注意!发生死锁时一定有循环等待,但是发生循环等待时未必死锁(循环等待是死锁的必要不充分件)
如果同类资源数大于1,则即使有循环等待,也未必发生死锁。但如果系统中每类资源都只有一个,那循环等待就是死锁的充分必要条件了。
死锁的避免:只要使其中一个条件不满足就无法形成死锁。