D. 项目文档#
本章介绍了一个可能的实现的示例分配和填充的设计文档。 其目的是让您了解我们希望在您自己的设计文档中看到的内容。
D.1 Sample Assignment#
Implement thread_join()
.
Function: void thread_join (tid_t tid)
阻塞当前线程,直到线程tid退出。 如果A是正在运行的线程,B是参数,那么我们说“A 加入 B”。
顺便说一句,参数是线程 id,而不是线程指针,因为线程指针在时间上不是唯一的。 也就是说,当一个线程死亡时,它的内存可能会立即或稍后被另一个线程重用。 如果线程 A 随着时间的推移有两个子 B 和 C 存储在相同的地址,那么 thread_join(B)
和 thread_join(C)
将是不明确的。
线程只能加入其直接子级。 在不是调用者子线程的线程上调用 thread_join()
应该会导致调用者立即返回。 孩子不是“继承的”,也就是说,如果 A 有孩子 B,B 有孩子 C,那么如果 A 尝试加入 C,即使 B 已经死了,它也总是会立即返回。
永远不需要加入线程。 您的解决方案应该正确释放线程的所有资源,包括它的struct thread
,无论它是否曾经加入,也无论子节点是在其父节点之前还是之后退出。 也就是说,一个线程在所有情况下都应该只被释放一次。
加入给定线程是幂等的。 也就是多次加入一个线程就相当于加入一次,因为在后面加入的时候它已经退出了。 因此,在第一个线程之后的给定线程上的连接应该立即返回。
您必须处理可能发生连接的所有方式:嵌套join(A join B,然后 B join C)、多重join(A join B,然后 A join C)等等。
D.2 Sample Design Document#
+-----------------+
| CS 140 |
| SAMPLE PROJECT |
| DESIGN DOCUMENT |
+-----------------+
---- GROUP ----
Ben Pfaff blp@stanford.edu
---- PRELIMINARIES ----
If you have any preliminary comments on your submission, notes for the TAs, or extra credit, please give them here.
(This is a sample design document.)
请引用您在准备提交时咨询的任何离线或在线资源,除了 Pintos 文档,课文和讲义。
None.
JOIN
====
---- 数据结构 ----
Copy here the declaration of each new or changed `struct' or `struct' member, global or static variable, `typedef', or enumeration. Identify the purpose of each in 25 words or less.
“锁存器”是一种新的同步原语。 获取块 直到第一次发布。 之后,所有正在进行的和未来的 立即获得通过。
/\* Latch. \*/
struct latch
{
bool released; /\* Released yet? \*/
struct lock monitor\_lock; /\* Monitor lock. \*/
struct condition rel\_cond; /\* Signaled when released. \*/
};
Added to struct thread:
/\* Members for implementing thread\_join(). \*/
struct latch ready\_to\_die; /\* Release when thread about to die. \*/
struct semaphore can\_die; /\* Up when thread allowed to die. \*/
struct list children; /\* List of child threads. \*/
list\_elem children\_elem; /\* Element of \`children' list. \*/
---- 算法 ----
Briefly describe your implementation of thread_join() and how it interacts with thread termination.
thread_join() finds the joined child on the thread's list of children and waits for the child to exit by acquiring the child's ready_to_die latch. When thread_exit() is called, the thread releases its ready_to_die latch, allowing the parent to continue.
---- 同步 ----
Consider parent thread P with child thread C. How do you ensure proper synchronization and avoid race conditions when P calls wait(C) before C exits? After C exits? How do you ensure that all resources are freed in each case? How about when P terminates without waiting, before C exits? After C exits? Are there any special cases?
C 在 thread_exit() 中等待 P 在完成自己的退出之前死亡,使用 C 的“down”和 P 退出时“up”的 can_die 信号量。 不管 C 是否终止,wait(C) 上都没有竞争,因为 C 在释放自己之前等待 P 的许可。
不管 P 是否等待 C,当 P 死亡时,P 仍然会“up”s C 的 can_die 信号量,因此 C 将始终被释放。 (但是,释放 C 的资源会延迟到 P 死亡。)
初始线程是一种特殊情况,因为它没有父线程等待它或“启动”它的 can_die 信号量。 因此,它的 can_die 信号量被初始化为 1。
---- RATIONALE ----
评价您的设计,指出您的设计选择中的优点和缺点。
这种设计的优点是简单。 封装最多 将同步逻辑转换为新的“锁存器”结构 将存在的小复杂性抽象到一个单独的层中, 使设计更容易推理。 此外,所有新数据 成员在`struct thread'中,不需要任何额外的动态 分配等,这将需要额外的管理代码。
另一方面,这种设计是浪费的,因为一个子线程 在其父级终止之前无法释放自己。 家长 创建大量短期子线程的线程 可能不必要地耗尽内核内存。 这大概是 可以接受实现内核线程,但它可能是一个坏的 与用户进程一起使用的想法,因为数量较多 用户进程倾向于拥有的资源。