操作系统导论习题解答(27. Thread API)
Interlude: Thread API
带着两个问题学习本章节:
- OS创造和控制线程预留了什么接口?
- 这些接口是如何被设计以实现易用性和实用性?
1. Thread Creation
2. Thread Completion
3. Locks
除了创建和加入线程,另一个最有用的函数集就是为了使关键部分互斥的lcoks。
下面是一对函数:
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
上述一对函数的使用非常简单,就是把关键部分的代码置于其中:
当然,如果一个线程已经调用了lock,那么其他线程如果想调用lock的话就必须等待上一个调用lock的线程unlock。
不幸的是,该代码被两个重要问题破坏了:
- lack of proper initialization
- it fails to check error codes when calling lock and unlock
解决第一个问题的方法有两种初始化(静态和动态分配)。
// 静态分配
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
// 动态分配
int rc = pthread_mutex_init(&lock, NULL);
assert(rc == 0);
pthread_mutex_destroy(rc); // 记得最后对动态分配要回收
简单程序使用assert,当出现问题时,更复杂的程序不是简单的退出,而是检查错误,并在调用不成功时进行适当处理。下面是一个简单程序:
关于lock还有两个函数可调用:
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_timedlock(pthread_mutex_t *mutex, struct timespec *abs_timeout);
这两个调用函数用于lcok获取。如果已持有lock,那么trylock
将返回失败;获取lock的timedlock
当超时或者获取lock后返回。
4. Condition Variables
当线程之间必须进行某种类型的信号传递时,如果一个线程在等待另一个线程做一些事情才能继续执行,则condition variables非常有用。希望以这种方式进行交互的程序使用如下可调用函数:
int pthread_cond_wait(pthread_cont_t *cond, pthread_mutex_t *mutex);
int pthread_cond_signal(pthread_cond_t *cond);
第一个pthread_cond_wait
使调用线程进入睡眠状态,等待其他线程发出信号。
如下所示:
为了唤醒上述进入等待(睡眠)状态线程,有如下代码:
值得注意的是为了防止race condition,我们把condition variable放置在lock中。
对于pthread_cond_wait
和pthread_cond_signal
来说,传递参数不同。如下所示:
// wait多了一个lock参数是因为当调用该函数时就进行unlock
// 然后传入的lock参数与phread_mutex_unlock(&lock)进行匹配
pthread_cond_wait(&cond, &lock);
pthread_cond_signal(&cond);
其实,单从代码的角度来说,可以把上述代码的while
循环改写成如下:
while (ready == 0)
; // spin
但是,最好不要如此做。有如下几个原因:
- 它在许多情况下性能不佳(长时间循环只会浪费CPU周期)
- 容易出错
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端