select阻塞的原理是什么,结合select的源代码讲解
时间: 2024-03-11 09:02:36 浏览: 72
select 函数的阻塞原理是在内核中维护一个等待队列,当 select 函数被调用时,会将进程的文件描述符集合(readfds、writefds、exceptfds)和超时时间传递给内核,内核会遍历这些文件描述符,判断是否有描述符的状态发生了变化。如果没有任何描述符的状态发生变化,select 就会阻塞等待,直到有描述符的状态发生了变化或者超时时间到达。
下面是 select 函数的简化版源代码,以便更好地理解它的阻塞原理:
```c
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout)
{
/* 将进程的文件描述符集合复制到内核中 */
fd_set rfds, wfds, efds;
memcpy(&rfds, readfds, sizeof(fd_set));
memcpy(&wfds, writefds, sizeof(fd_set));
memcpy(&efds, exceptfds, sizeof(fd_set));
/* 构造等待队列 */
struct poll_table_entry table;
table.rq = current;
table.polling = true;
table.key = POLLIN | POLLOUT | POLLPRI;
/* 遍历文件描述符集合,判断是否有描述符的状态发生变化 */
while (true) {
/* 遍历读集合,判断是否有可读描述符 */
for (int fd = 0; fd < nfds; fd++) {
if (FD_ISSET(fd, readfds) && is_readable(fd)) {
return fd;
}
}
/* 遍历写集合,判断是否有可写描述符 */
for (int fd = 0; fd < nfds; fd++) {
if (FD_ISSET(fd, writefds) && is_writable(fd)) {
return fd;
}
}
/* 没有找到符合条件的描述符,阻塞等待 */
sleep_on_poll_table(&table, timeout);
}
return -1;
}
```
这个简化版的 select 函数在进程调用时,会将进程的文件描述符集合复制到内核中,并构造等待队列。然后,它会遍历读集合和写集合,判断是否有描述符的状态发生了变化。如果没有找到符合条件的描述符,就会调用 `sleep_on_poll_table` 函数阻塞等待,直到有描述符的状态发生变化或者超时时间到达。
需要注意的是,这个简化版的 select 函数并不完整,实际的 select 函数还支持检查错误异常条件等。但是,它基本上涵盖了 select 函数的阻塞原理。
阅读全文