面试题答案
一键面试互斥锁(Mutex)
- 工作原理:互斥锁是一种二元信号量,它只有两种状态:锁定(locked)和解锁(unlocked)。当一个线程想要访问共享资源时,它必须先获取互斥锁。如果互斥锁处于解锁状态,线程可以获取它并将其锁定,这样其他线程就无法获取该互斥锁,直到该线程释放它(解锁)。通过这种方式,确保同一时间只有一个线程能够访问共享资源,从而避免竞态条件。
- 网络服务器开发场景示例:在一个多线程的HTTP服务器中,可能有多个线程同时处理客户端请求,而这些请求可能会访问共享的日志文件(用于记录访问日志)。为了避免多个线程同时写入日志文件导致数据混乱,每个线程在写入日志前先获取互斥锁,写完后释放互斥锁。
信号量(Semaphore)
- 工作原理:信号量维护着一个计数器,该计数器表示当前可用的资源数量。线程在访问共享资源前,需要先获取信号量。如果计数器大于0,线程获取信号量成功,计数器减1;如果计数器为0,线程会被阻塞,直到其他线程释放信号量(计数器加1)。当线程使用完共享资源后,释放信号量,计数器加1。通过控制计数器的值,可以限制同时访问共享资源的线程数量,进而避免竞态条件。
- 网络服务器开发场景示例:在数据库连接池的实现中,假设连接池有固定数量的数据库连接(例如10个)。信号量的计数器初始值设为10,表示有10个可用连接。当一个线程需要连接数据库时,获取信号量,如果获取成功,就从连接池中取出一个连接使用。使用完毕后,释放信号量,连接放回连接池。这样可以确保不会有超过10个线程同时使用数据库连接,避免因过多线程同时访问数据库造成数据库负载过高或数据不一致问题。
条件变量(Condition Variable)
- 工作原理:条件变量通常与互斥锁一起使用。线程可以在某个条件满足时等待在条件变量上,此时线程会释放它持有的互斥锁并进入睡眠状态。当另一个线程改变了相关条件后,通过通知条件变量,唤醒等待在该条件变量上的一个或多个线程。被唤醒的线程重新获取互斥锁,然后检查条件是否满足,如果满足则继续执行。这样可以保证线程在合适的条件下访问共享资源,避免竞态条件。
- 网络服务器开发场景示例:在一个基于多线程的文件传输服务器中,主线程负责接收客户端的文件传输请求并将请求放入任务队列。工作线程从任务队列中取出任务进行处理。当任务队列为空时,工作线程可以等待在条件变量上,并释放持有的互斥锁(该互斥锁用于保护任务队列的访问)。当主线程向任务队列添加新任务后,通知条件变量,唤醒一个工作线程,工作线程重新获取互斥锁,从任务队列中取出任务并处理。