学习笔记7
第四章 并发编程
线程
在进程模型中,进程是独立的执行单元。所有进程均在内核模式或用户模式下执行。
在内核模式下,各进程在唯一地址空间上执行,与其他进程分开,但只有一个执行路径。
线程是某进程同一地址空间上独立执行单元。创建某个进程就是在一个唯一地址空间创建一个主线程,线程又可以创建线程,但某进程的所有线程都在该进程的相同地址空间中执行。
线程共享进程的许多资源。
线程的优点:
线程创建和切换速度更快:
进程的上下文复杂而庞大,要想创建新的进程,操作系统必须为进程分配内存表并构建页表,而创建线程不用。
进程切换涉及将一个进程的复杂分页环境切换为另一个,相比之下线程切换只需操作系统内核切换执行点,而不需要更改进程映像。
线程的响应速度更快:
一个进程只有一个执行路径,当某个进程被挂起时,整个进程都将停止执行;相反,某个线程被挂起时,同一进程中的其他线程可以继续执行。
线程更适合并行计算:
并行计算的目标是使用多个执行路径更快地解决问题。基于分治原则(如二叉树查找和快速排序等)的算法经常表现出高度的并行性,可通过使用并行或并发执行来提高计算速度。
在进程模型中,各进程不能有效共享数据,对此,进程必须使用进程间通信(IPC)来交换数据或使用其他方法将公用数据区包含到其地址空间中。
线程的缺点:
由于地址共享,线程需要来自用户的明确同步
许多库函数可能对线程不安全
在单CPU系统中更慢
线程操作
线程的执行轨迹与进程类似。线程可在内核模式或用户模式下执行。在用户模式下,线程在进程的相同地址空间中执行,但每个线程都有自己的执行堆栈。线程是独立的执行单元,可根据操作系统内核的调度策略,对内核进行系统调用,变为挂起、激活以继续执行等。
线程管理函数
Pthread库提供了用于线程管理的以下API:
pthread_create(thread,attr,function,arg):create thread
pthread_exit(status):terminate thread
pthread_cancel(thread):cancel thread
pthread_attr_init(attr):initialize thread attributes
pthread_attr_destroy(attr):destroy thread attribute
创建线程
int pthread_create (pthread_t *pthread_id, pthread_attr_t *attr, void *(*func)(void *), void *arg);
线程ID
int pthread_equal (pthread_t t1, pthread_t t2);
线程终止
int pthread_exit (void *status);
线程连接
int pthread_join (pthread_t thread,void **status_ptr);
一个线程可以等待另一个线程的终止,终止线程的退出状态以status_ptr返回。
线程同步
当多个线程试图修改统一共享变量或数据结构时,如果修改结果取决于线程的执行顺序,则称之为竞争条件。
为防止出现竞态条件并且支持线程协作,线程需要同步。
通常,同步是一种机制和规则,用于确保共享数据对象的完整性和并发执行实体的协调性。它可以用于内核模式下的进程,也可以应用于用户模式下的线程。
互斥量
最简单的同步工具是锁,在pthread中被称为互斥量,意思是相互排斥。
互斥量使用封锁协议。如果某线程不能获取互斥量,就会被阻塞,等待互斥量解锁后再继续。
但交叉等待会出现死锁
条件变量
当使用条件变量时,线程必须获取相关的互斥量。然后,它在互斥量的临界区内执行操作,释放互斥量
信息量
信息量是进程同步的一般机制。
struct sem{
int value; //semaphore (counter) value;
struct progress *queue //a queue of blocked processes
}s;
信息量和条件变量之间的主要区别是前者包含一个计数器,可操作计数器,测试计数器值以做出决策;而后者需要一个特定的互斥量来执行临界区。