user-0 提问: 操作系统的进程堵塞概念

回复:
user: user-1
content: 引用 楼主 u012879806 的回复:问题1：   现代操作系统 这本书上提到进程堵塞概念：  即使cpu不空闲，也不会执行进程，  这就是堵塞。  好了， 我们结合具体的一款操作系统windows， 请问 sleep函数， 会让进程堵塞吗？   如果不会，为什么？   windows也是一操作系统，所以它的堵塞概念，也得和 操作系统书本保持一致。   sleep这个时间段内，进程没法运行， 所以也叫堵塞。  线程没法运行，也叫堵塞。  同理waitforsingleobject等函数，也是如此。  以上是我对进程，线程堵塞理解。    问题2： windows 有很多堵塞函数，比如网络库函数recv等，也会让线程堵塞。  可是有的函数堵塞会消耗cpu，有的则不会。 什么原因导致这么大的差异？   还有既然堵塞了进程。 进程就没有cpu，没有cpu，何来 消耗cpu一说呢？ sleep的作用就是让直行线程加入等待队列,合适的时候唤醒,以下情况使用sleep就醒不来了, 硬中断上下文, 某些情况软中断上下文.

user: user-2
content: 所有真正的阻塞都不会占用CPU， 如果非说占用一点的话就是进程切换或者进入内核的开销， 这个可能会有点差异吧    有些人写程序用无意义的循环做阻塞，这是个人问题而且那不符合阻塞的定义， 进程是照常跑的， 只是这部分执行的代码无意义而已

user: user-3

user: user-4
content: http://technet.microsoft.com/en-us/Sysinternals/bb897540.aspx

user: user-0
content: 引用 13 楼 u012879787 的回复:[quote=引用 12 楼 zhao4zhong1 的回复:] C:\windows_2000_source_code\win2k\private\net\sockets\winsock2\dll\winsock2\recv.cpp      43: int WSAAPI      44: recv(      45:      IN SOCKET s,      46:      OUT char FAR * buf,      47:      IN int len,      48:      IN int flags      49:      )      50: /*++      51: Routine Description:      52:       53:     Receive data from a socket.      54:       55: Arguments:      56:       57:     s     - A descriptor identifying a connected socket.      58:       59:     buf   - A buffer for the incoming data.      60:       61:     len   - The length of buf.      62:       63:     flags - Specifies the way in which the call is made.      64:       65: Returns:      66:       67:     The  number  of  bytes  received.   If  the  connection has been gracefully      68:     closed,  the  return  value  is  0.   Otherwise, a value of SOCKET_ERROR is      69:     returned, and a specific error code is stored with SetErrorCode().      70:       71: --*/      72:       73: {      74:     INT             ErrorCode;      75:     PDSOCKET        Socket;      76:     LPWSATHREADID   ThreadId;      77:       78:       79:     ErrorCode = TURBO_PROLOG_OVLP(&ThreadId);      80:     if (ErrorCode==ERROR_SUCCESS)      81:     {      82:         Socket = DSOCKET::GetCountedDSocketFromSocket(s);      83:         if(Socket != NULL){      84:             INT             ReturnValue;      85:             PDPROVIDER      Provider;      86:             DWORD           BytesReceived;      87:             WSABUF          Buffers;      88:       89:             Buffers.len = len;      90:             Buffers.buf = buf;      91:       92:             Provider = Socket->GetDProvider();      93:             ReturnValue = Provider->WSPRecv(s,      94:                               &Buffers,      95:                               1,      96:                               &BytesReceived,      97:                               (LPDWORD)&flags,      98:                               NULL,                 // lpOverlapped      99:                               NULL,                 // lpCompletionRoutine     100:                               ThreadId,     101:                               &ErrorCode);     102:             Socket->DropDSocketReference();     103:             if (ReturnValue==ERROR_SUCCESS) {     104:                 if ((flags & MSG_PARTIAL)==0) {     105:                     return (INT)BytesReceived;     106:                 }     107:                 ErrorCode = WSAEMSGSIZE;     108:             }     109:      110:             assert (ErrorCode!=NO_ERROR);     111:             if (ErrorCode==NO_ERROR)     112:                 ErrorCode = WSASYSCALLFAILURE;     113:      114:         }     115:         else {     116:             ErrorCode = WSAENOTSOCK;     117:         }     118:     }     119:      120:     SetLastError(ErrorCode);     121:     return SOCKET_ERROR;     122: }    这2000的代码 和我想象的不一样。我还以为是内部开辟个线程，然后等待线程返回，  所以给用户造成一种现象：等待。  感谢你的参与。    问题2： windows 有很多堵塞函数，比如网络库函数recv等，也会让线程堵塞。  可是有的函数堵塞会消耗cpu，有的则不会。 什么原因导致这么大的差异？   还有既然堵塞了进程。 进程就没有cpu，没有cpu，何来 消耗cpu一说呢？   这问题，是错误的，需要更正，更正为： 一些网络函数，被堵塞后， 未必进程会堵塞，比如你放在一个子线程里，  所以这种，不算进程堵塞， 但是算线程堵塞。 这些函数，会消耗 cpu。   原因，目前没有能力彻底搞清楚， 跳过。   最后一个问题，  有没有工具，可以查看某个 进程处于：运行，就绪，堵塞 的状态？   任务管理器无法胜任此项工作。  [/quote]   windows下没有进程调度的说法， 所以不存在进程堵塞、运行、等待 这种状态。

user: user-4
content: 举例来讲：recv阻塞了，但其底层实现对应的通过网卡接收字节的线程不能阻塞，仍需消耗cpu。 说的不对的话，请楼下高手拍砖。   《Windows编程启示录》 19.6 为什么有些进程在被终止之后还停留在任务管理器中     当某个进程结束时（可能是正常结束，也可能是因为调用了像TerminateProcess之类的函数），这个进程的用户态模块将被删除。但内核态模块只有在与线程相关的所有驱动程序执行完成之后才会被删除。     例如，如果某个线程正处于I/O操作中，那么将会给负责I/O的驱动程序发送一个内核信号来取消这个操作。     如果驱动程序的行为是良好的，那么它将清除与这个未完成I/O相关的一些信息并且释放线程。     如果驱动程序的行为是不好的（可能是因为驱动程序管理的硬件表现出奇怪的行为），那么可能需要花很长的时间来清除这个未完成的I/O。在这段时间里，驱动程序将不会释放这个线程（以及这个线程所在的进程）。实际的情况要更复杂一些，但这里的简单模型对于我们的讨论已经足够。    ……    换句话说，如果你终止了某个进程后还能在任务管理器中看到这个进程，那么实际上这个进程已经停止运行了，只不过还有些残留的信息保留在系统中，只有当与这个进程相关的所有驱动程序都完成了清除操作并且指向这个进程的句柄都已经关闭，进程才会完全消失。

user: user-5
content: 引用 6 楼 u012879806 的回复:[quote=引用 4 楼 max_min_ 的回复:] 即使cpu不空闲，也不会执行进程  sleep是在只执行进程的，只是这个进程在sleep而已！<不考虑线程>  windows下 sleep是针对线程而言  如果程序只有一个线程，恰好该线程里调用 sleep， getch ,getchar等函数，  我感觉 进程就会堵塞。  此时， 系统分配cpu给 该进程，那么程序也不会继续执行，  因为等待某个事件发生，比如：输入事件， 或者sleep时间到了，才会 继续。   我好奇的是：   为什么有的阻塞函数会消耗cpu，有的则不会，  有高手指导吗？  [/quote] 有的虽然阻塞了，但还是在执行汇编指令，例如while(1),但sleep不会，sleep让线程主动放弃时间片，CPU不会去执行任何代码，当然不消耗CPU了

user: user-0
content: 引用 4 楼 max_min_ 的回复:即使cpu不空闲，也不会执行进程  sleep是在只执行进程的，只是这个进程在sleep而已！<不考虑线程>  windows下 sleep是针对线程而言  如果程序只有一个线程，恰好该线程里调用 sleep， getch ,getchar等函数，  我感觉 进程就会堵塞。  此时， 系统分配cpu给 该进程，那么程序也不会继续执行，  因为等待某个事件发生，比如：输入事件， 或者sleep时间到了，才会 继续。   我好奇的是：   为什么有的阻塞函数会消耗cpu，有的则不会，  有高手指导吗？

user: user-4
content: 建议精读Linux源代码中有关线程调度的源代码。 《深入解析Windows操作系统-Windows Internals》 《30天自制操作系统》

user: user-6
content: 引用 12 楼 zhao4zhong1 的回复:C:\windows_2000_source_code\win2k\private\net\sockets\winsock2\dll\winsock2\recv.cpp      43: int WSAAPI      44: recv(      45:      IN SOCKET s,      46:      OUT char FAR * buf,      47:      IN int len,      48:      IN int flags      49:      )      50: /*++      51: Routine Description:      52:       53:     Receive data from a socket.      54:       55: Arguments:      56:       57:     s     - A descriptor identifying a connected socket.      58:       59:     buf   - A buffer for the incoming data.      60:       61:     len   - The length of buf.      62:       63:     flags - Specifies the way in which the call is made.      64:       65: Returns:      66:       67:     The  number  of  bytes  received.   If  the  connection has been gracefully      68:     closed,  the  return  value  is  0.   Otherwise, a value of SOCKET_ERROR is      69:     returned, and a specific error code is stored with SetErrorCode().      70:       71: --*/      72:       73: {      74:     INT             ErrorCode;      75:     PDSOCKET        Socket;      76:     LPWSATHREADID   ThreadId;      77:       78:       79:     ErrorCode = TURBO_PROLOG_OVLP(&ThreadId);      80:     if (ErrorCode==ERROR_SUCCESS)      81:     {      82:         Socket = DSOCKET::GetCountedDSocketFromSocket(s);      83:         if(Socket != NULL){      84:             INT             ReturnValue;      85:             PDPROVIDER      Provider;      86:             DWORD           BytesReceived;      87:             WSABUF          Buffers;      88:       89:             Buffers.len = len;      90:             Buffers.buf = buf;      91:       92:             Provider = Socket->GetDProvider();      93:             ReturnValue = Provider->WSPRecv(s,      94:                               &Buffers,      95:                               1,      96:                               &BytesReceived,      97:                               (LPDWORD)&flags,      98:                               NULL,                 // lpOverlapped      99:                               NULL,                 // lpCompletionRoutine     100:                               ThreadId,     101:                               &ErrorCode);     102:             Socket->DropDSocketReference();     103:             if (ReturnValue==ERROR_SUCCESS) {     104:                 if ((flags & MSG_PARTIAL)==0) {     105:                     return (INT)BytesReceived;     106:                 }     107:                 ErrorCode = WSAEMSGSIZE;     108:             }     109:      110:             assert (ErrorCode!=NO_ERROR);     111:             if (ErrorCode==NO_ERROR)     112:                 ErrorCode = WSASYSCALLFAILURE;     113:      114:         }     115:         else {     116:             ErrorCode = WSAENOTSOCK;     117:         }     118:     }     119:      120:     SetLastError(ErrorCode);     121:     return SOCKET_ERROR;     122: }    这2000的代码 和我想象的不一样。我还以为是内部开辟个线程，然后等待线程返回，  所以给用户造成一种现象：等待。  感谢你的参与。    问题2： windows 有很多堵塞函数，比如网络库函数recv等，也会让线程堵塞。  可是有的函数堵塞会消耗cpu，有的则不会。 什么原因导致这么大的差异？   还有既然堵塞了进程。 进程就没有cpu，没有cpu，何来 消耗cpu一说呢？   这问题，是错误的，需要更正，更正为： 一些网络函数，被堵塞后， 未必进程会堵塞，比如你放在一个子线程里，  所以这种，不算进程堵塞， 但是算线程堵塞。 这些函数，会消耗 cpu。   原因，目前没有能力彻底搞清楚， 跳过。   最后一个问题，  有没有工具，可以查看某个 进程处于：运行，就绪，堵塞 的状态？   任务管理器无法胜任此项工作。

user: user-4
content: C:\windows_2000_source_code\win2k\private\net\sockets\winsock2\dll\winsock2\recv.cpp      43: int WSAAPI      44: recv(      45:      IN SOCKET s,      46:      OUT char FAR * buf,      47:      IN int len,      48:      IN int flags      49:      )      50: /*++      51: Routine Description:      52:       53:     Receive data from a socket.      54:       55: Arguments:      56:       57:     s     - A descriptor identifying a connected socket.      58:       59:     buf   - A buffer for the incoming data.      60:       61:     len   - The length of buf.      62:       63:     flags - Specifies the way in which the call is made.      64:       65: Returns:      66:       67:     The  number  of  bytes  received.   If  the  connection has been gracefully      68:     closed,  the  return  value  is  0.   Otherwise, a value of SOCKET_ERROR is      69:     returned, and a specific error code is stored with SetErrorCode().      70:       71: --*/      72:       73: {      74:     INT             ErrorCode;      75:     PDSOCKET        Socket;      76:     LPWSATHREADID   ThreadId;      77:       78:       79:     ErrorCode = TURBO_PROLOG_OVLP(&ThreadId);      80:     if (ErrorCode==ERROR_SUCCESS)      81:     {      82:         Socket = DSOCKET::GetCountedDSocketFromSocket(s);      83:         if(Socket != NULL){      84:             INT             ReturnValue;      85:             PDPROVIDER      Provider;      86:             DWORD           BytesReceived;      87:             WSABUF          Buffers;      88:       89:             Buffers.len = len;      90:             Buffers.buf = buf;      91:       92:             Provider = Socket->GetDProvider();      93:             ReturnValue = Provider->WSPRecv(s,      94:                               &Buffers,      95:                               1,      96:                               &BytesReceived,      97:                               (LPDWORD)&flags,      98:                               NULL,                 // lpOverlapped      99:                               NULL,                 // lpCompletionRoutine     100:                               ThreadId,     101:                               &ErrorCode);     102:             Socket->DropDSocketReference();     103:             if (ReturnValue==ERROR_SUCCESS) {     104:                 if ((flags & MSG_PARTIAL)==0) {     105:                     return (INT)BytesReceived;     106:                 }     107:                 ErrorCode = WSAEMSGSIZE;     108:             }     109:      110:             assert (ErrorCode!=NO_ERROR);     111:             if (ErrorCode==NO_ERROR)     112:                 ErrorCode = WSASYSCALLFAILURE;     113:      114:         }     115:         else {     116:             ErrorCode = WSAENOTSOCK;     117:         }     118:     }     119:      120:     SetLastError(ErrorCode);     121:     return SOCKET_ERROR;     122: }

user: user-4
content: recv函数所在线程不消耗CPU，但recv函数需要完成的功能这个接力棒被传给socket底层对应线程继续消耗CPU了。我猜。

user: user-7
content: 即使cpu不空闲，也不会执行进程  sleep是在只执行进程的，只是这个进程在sleep而已！<不考虑线程>

user: user-8
content: 我是新人, 我很好奇 sleep 不是 sleep 线程吗?

user: user-6
content: 引用 7 楼 bigbaldy 的回复:[quote=引用 6 楼 u012879806 的回复:] [quote=引用 4 楼 max_min_ 的回复:] 即使cpu不空闲，也不会执行进程  sleep是在只执行进程的，只是这个进程在sleep而已！<不考虑线程>  windows下 sleep是针对线程而言  如果程序只有一个线程，恰好该线程里调用 sleep， getch ,getchar等函数，  我感觉 进程就会堵塞。  此时， 系统分配cpu给 该进程，那么程序也不会继续执行，  因为等待某个事件发生，比如：输入事件， 或者sleep时间到了，才会 继续。   我好奇的是：   为什么有的阻塞函数会消耗cpu，有的则不会，  有高手指导吗？  [/quote] 有的虽然阻塞了，但还是在执行汇编指令，例如while(1),但sleep不会，sleep让线程主动放弃时间片，CPU不会去执行任何代码，当然不消耗CPU了[/quote]  看9楼。

user: user-6
content: 引用 8 楼 zhao4zhong1 的回复:举例来讲：recv阻塞了，但其底层实现对应的通过网卡接收字节的线程不能阻塞，仍需消耗cpu。 说的不对的话，请楼下高手拍砖。   《Windows编程启示录》 19.6 为什么有些进程在被终止之后还停留在任务管理器中     当某个进程结束时（可能是正常结束，也可能是因为调用了像TerminateProcess之类的函数），这个进程的用户态模块将被删除。但内核态模块只有在与线程相关的所有驱动程序执行完成之后才会被删除。     例如，如果某个线程正处于I/O操作中，那么将会给负责I/O的驱动程序发送一个内核信号来取消这个操作。     如果驱动程序的行为是良好的，那么它将清除与这个未完成I/O相关的一些信息并且释放线程。     如果驱动程序的行为是不好的（可能是因为驱动程序管理的硬件表现出奇怪的行为），那么可能需要花很长的时间来清除这个未完成的I/O。在这段时间里，驱动程序将不会释放这个线程（以及这个线程所在的进程）。实际的情况要更复杂一些，但这里的简单模型对于我们的讨论已经足够。    ……    换句话说，如果你终止了某个进程后还能在任务管理器中看到这个进程，那么实际上这个进程已经停止运行了，只不过还有些残留的信息保留在系统中，只有当与这个进程相关的所有驱动程序都完成了清除操作并且指向这个进程的句柄都已经关闭，进程才会完全消失。   我给你跟更正一下。。  recv 对用户来说只是一个api， 它自身内部，是否用while这种循环，没看过反汇编源码，  所以我不得而知。  一个api的内部实现， 哪怕它是用循环语句，或者内部再次开辟一个子线程，然后再傻等待这个子线程结束。  对用户来说，我们是不会管他怎么实现的。  用户只会关心，该函数堵塞的时候，是否会消耗cpu ,  很明显 recv 是会消耗， 会消耗的说法，是来自网络，我没有发自验证它。  既然会消耗，那么其内部 不应该是：  recv () { HANDLE hThread = _beingthreadex(...); if(!hThread ) return; waitforsingleobject(hThread, -1); }  sleep， wait.. 等函数，均不会消耗cpu。  只会让出cpu来。

user: user-0
content: 高手额？ ？？

user: user-9
content: 路过。。。学知识。。