三、消息循环
2015-01-14 11:48
316 查看
三 消息循环
看服端的主体:live555MediaServer.cpp 中的 main()函数,可见其创建一个 RTSPServer
类实例后,即进入一个函数 env->taskScheduler().doEventLoop()中,看名字很明显是一个
消息循坏,执行到里面后不停地转圈,生名不息,转圈不止。那么在这个人生的圈圈中如何
实现 RTSP 服务和 RTP 传输呢?别想那么远了,还是先看这个圈圈中实现了什么功能吧。
[cpp]
1. void BasicTaskScheduler0::doEventLoop(char* watchVariable) {
2. // Repeatedly loop, handling readble sockets and timed events:
3. while (1) {
4. if (watchVariable != NULL && *watchVariable != 0)
5. break;
6. SingleStep();
7. }
8. }
BasicTaskScheduler0 从 TaskScheduler 派生,所以还是一个任务调度对象,所以依然说
明任务调度对象是整个程序的发动机。
循环中每次走一步:SingleStep()。这走一步中都做些什么呢? 总结为以下四步:
1为所有需要操作的 socket 执行 select。
2找出第一个应执行的 socket 任务(handler)并执行之。
3找到第一个应响应的事件,并执行之。
4找到第一个应执行的延迟任务并执行之。
可见,每一步中只执行三个任务队列中的一项。下面详细分析函数 SingleStep():
[cpp] view plaincopyprint?
1. //循坏中主要执行的函数
2. void BasicTaskScheduler::SingleStep(unsigned maxDelayTime) {
3. fd_set readSet = fReadSet; // make a copy for this select() call
4. fd_set writeSet = fWriteSet; // ditto
5. fd_set exceptionSet = fExceptionSet; // ditto
6.
7. //计算 select socket 们时的超时时间。
8. DelayInterval const& timeToDelay = fDelayQueue.timeToNextAlarm();
9. struct timeval tv_timeToDelay;
10. tv_timeToDelay.tv_sec = timeToDelay.seconds();
11. tv_timeToDelay.tv_usec = timeToDelay.useconds();
12. // Very large "tv_sec" values cause select() to fail.
13. // Don't make it any larger than 1 million seconds (11.5 days)
14. const long MAX_TV_SEC = MILLION;
15. if (tv_timeToDelay.tv_sec > MAX_TV_SEC) {
16. tv_timeToDelay.tv_sec = MAX_TV_SEC;
17. }
18. // Also check our "maxDelayTime" parameter (if it's > 0):
19. if (maxDelayTime > 0
20. && (tv_timeToDelay.tv_sec > (long) maxDelayTime / MILLION
21. || (tv_timeToDelay.tv_sec == (long) maxDelayTime / MILLION
22. && tv_timeToDelay.tv_usec
23. > (long) maxDelayTime % MILLION))) { 24. tv_timeToDelay.tv_sec = maxDelayTime / MILLION;
25. tv_timeToDelay.tv_usec = maxDelayTime % MILLION;
26. }
27.
28. //先执行 socket 的 select 操作,以确定哪些 socket 任务(handler)需要执行。
29. int selectResult = select(fMaxNumSockets,
30. &readSet, &writeSet,&exceptionSet,
31. &tv_timeToDelay);
32.
33. if (selectResult < 0) {
34. //#if defined(__WIN32__) || defined(_WIN32)
35. int err = WSAGetLastError();
36. // For some unknown reason, select() in Windoze sometimes fails with W
SAEINVAL if
37. // it was called with no entries set in "readSet". If this happens, ignore it:
38. if (err == WSAEINVAL && readSet.fd_count == 0) {
39. err = EINTR;
40. // To stop this from happening again, create a dummy socket:
41. int dummySocketNum = socket(AF_INET, SOCK_DGRAM, 0);
42. FD_SET((unsigned) dummySocketNum, &fReadSet);
43. }
44. if (err != EINTR) {
45. //#else
46. // if (errno != EINTR && errno != EAGAIN) {
47. //#endif
48. // Unexpected error - treat this as fatal:
49. //#if !defined(_WIN32_WCE)
50. // perror("BasicTaskScheduler::SingleStep(): select() fails");
51. //#endif
52. internalError();
53. }
54. }
55.
56. // Call the handler function for one readable socket: 57. HandlerIterator iter(*fHandlers);
58. HandlerDescriptor* handler;
59. // To ensure forward progress through the handlers, begin past the last
60. // socket number that we handled:
61. if (fLastHandledSocketNum >= 0) {
62. //找到上次执行的 socket handler 的下一个
63. while ((handler = iter.next()) != NULL) {
64. if (handler->socketNum == fLastHandledSocketNum)
65. break;
66. }
67. if (handler == NULL) {
68. fLastHandledSocketNum = -1;
69. iter.reset(); // start from the beginning instead
70. }
71. }
72.
73. //从找到的 handler 开始,找一个可以执行的 handler,不论其状态是可读,可
写,还是出错,执行之。
74. while ((handler = iter.next()) != NULL) {
75. int sock = handler->socketNum; // alias
76. int resultConditionSet = 0;
77. if (FD_ISSET(sock, &readSet)
78. && FD_ISSET(sock, &fReadSet)/*sanity check*/)
79. resultConditionSet |= SOCKET_READABLE;
80. if (FD_ISSET(sock, &writeSet)
81. && FD_ISSET(sock, &fWriteSet)/*sanity check*/)
82. resultConditionSet |= SOCKET_WRITABLE;
83. if (FD_ISSET(sock, &exceptionSet)
84. && FD_ISSET(sock, &fExceptionSet)/*sanity check*/)
85. resultConditionSet |= SOCKET_EXCEPTION;
86. if ((resultConditionSet & handler->conditionSet)
87. != 0 && handler->handlerProc != NULL) {
88. fLastHandledSocketNum = sock;
89. // Note: we set "fLastHandledSocketNum" before calling the handler,
90. // in case the handler calls "doEventLoop()" reentrantly. 91. (*handler->handlerProc)(handler->clientData, resultConditionSet);
92. break;
93. }
94. }
95.
96. //如果寻找完了依然没有执行任何 handle,则从头再找。
97. if (handler == NULL && fLastHandledSocketNum >= 0) {
98. // We didn't call a handler, but we didn't get to check all of them,
99. // so try again from the beginning:
100. iter.reset();
101. while ((handler = iter.next()) != NULL) {
102. int sock = handler-&g
4000
t;socketNum; // alias
103. int resultConditionSet = 0;
104. if (FD_ISSET(sock, &readSet)&& FD_ISSET(sock, &fReadSet)/*san
ity check*/)
105. resultConditionSet |= SOCKET_READABLE;
106. if (FD_ISSET(sock, &writeSet)&& FD_ISSET(sock, &fWriteSet)/*san
ity check*/)
107. resultConditionSet |= SOCKET_WRITABLE;
108. if (FD_ISSET(sock, &exceptionSet) && FD_ISSET(sock, &fExcepti
onSet)/*sanity check*/)
109. resultConditionSet |= SOCKET_EXCEPTION;
110. if ((resultConditionSet & handler->conditionSet)
111. != 0 && handler->handlerProc != NULL) {
112. fLastHandledSocketNum = sock;
113. // Note: we set "fLastHandledSocketNum" before calling the handl
er,
114. // in case the handler calls "doEventLoop()" reentrantly.
115. (*handler->handlerProc)(handler->clientData, resultConditionSet);
116. break;
117. }
118. }
119. //依然没有找到可执行的 handler。
120. if (handler == NULL)
121. fLastHandledSocketNum = -1; //because we didn't call a handler 122. }
123. //响应事件
124. // Also handle any newly-triggered event
125. // (Note that we do this *after* calling a socket handler,
126. // in case the triggered event handler modifies The set of readable socket
s.)
127. if (fTriggersAwaitingHandling != 0) {
128. if (fTriggersAwaitingHandling == fLastUsedTriggerMask) {
129. // Common-case optimization for a single event trigger:
130. fTriggersAwaitingHandling = 0;
131. if (fTriggeredEventHandlers[fLastUsedTriggerNum] != NULL) {
132. //执行一个事件处理函数
133. (*fTriggeredEventHandlers[fLastUsedTriggerNum])(fTriggeredEv
entClientDatas[fLastUsedTriggerNum]);
134. }
135. } else {
136. // Look for an event trigger that needs handling
137. // (making sure that we make forward progress through all possible t
riggers):
138. unsigned i = fLastUsedTriggerNum;
139. EventTriggerId mask = fLastUsedTriggerMask;
140. do {
141. i = (i + 1) % MAX_NUM_EVENT_TRIGGERS;
142. mask >>= 1;
143. if (mask == 0)
144. mask = 0x80000000;
145. if ((fTriggersAwaitingHandling & mask) != 0) {
146. //执行一个事件响应
147. fTriggersAwaitingHandling &= ~mask;
148. if (fTriggeredEventHandlers[i] != NULL) {
149. (*fTriggeredEventHandlers[i])(fTriggeredEventClientDatas[i])
;
150. }
151. fLastUsedTriggerMask = mask;
152. fLastUsedTriggerNum = i; 153. break;
154. }
155. } while (i != fLastUsedTriggerNum);
156. }
157. }
158. //执行一个最迫切的延迟任务。
159. // Also handle any delayed event that may have come due.
160. fDelayQueue.handleAlarm();
161. }
看服端的主体:live555MediaServer.cpp 中的 main()函数,可见其创建一个 RTSPServer
类实例后,即进入一个函数 env->taskScheduler().doEventLoop()中,看名字很明显是一个
消息循坏,执行到里面后不停地转圈,生名不息,转圈不止。那么在这个人生的圈圈中如何
实现 RTSP 服务和 RTP 传输呢?别想那么远了,还是先看这个圈圈中实现了什么功能吧。
[cpp]
1. void BasicTaskScheduler0::doEventLoop(char* watchVariable) {
2. // Repeatedly loop, handling readble sockets and timed events:
3. while (1) {
4. if (watchVariable != NULL && *watchVariable != 0)
5. break;
6. SingleStep();
7. }
8. }
BasicTaskScheduler0 从 TaskScheduler 派生,所以还是一个任务调度对象,所以依然说
明任务调度对象是整个程序的发动机。
循环中每次走一步:SingleStep()。这走一步中都做些什么呢? 总结为以下四步:
1为所有需要操作的 socket 执行 select。
2找出第一个应执行的 socket 任务(handler)并执行之。
3找到第一个应响应的事件,并执行之。
4找到第一个应执行的延迟任务并执行之。
可见,每一步中只执行三个任务队列中的一项。下面详细分析函数 SingleStep():
[cpp] view plaincopyprint?
1. //循坏中主要执行的函数
2. void BasicTaskScheduler::SingleStep(unsigned maxDelayTime) {
3. fd_set readSet = fReadSet; // make a copy for this select() call
4. fd_set writeSet = fWriteSet; // ditto
5. fd_set exceptionSet = fExceptionSet; // ditto
6.
7. //计算 select socket 们时的超时时间。
8. DelayInterval const& timeToDelay = fDelayQueue.timeToNextAlarm();
9. struct timeval tv_timeToDelay;
10. tv_timeToDelay.tv_sec = timeToDelay.seconds();
11. tv_timeToDelay.tv_usec = timeToDelay.useconds();
12. // Very large "tv_sec" values cause select() to fail.
13. // Don't make it any larger than 1 million seconds (11.5 days)
14. const long MAX_TV_SEC = MILLION;
15. if (tv_timeToDelay.tv_sec > MAX_TV_SEC) {
16. tv_timeToDelay.tv_sec = MAX_TV_SEC;
17. }
18. // Also check our "maxDelayTime" parameter (if it's > 0):
19. if (maxDelayTime > 0
20. && (tv_timeToDelay.tv_sec > (long) maxDelayTime / MILLION
21. || (tv_timeToDelay.tv_sec == (long) maxDelayTime / MILLION
22. && tv_timeToDelay.tv_usec
23. > (long) maxDelayTime % MILLION))) { 24. tv_timeToDelay.tv_sec = maxDelayTime / MILLION;
25. tv_timeToDelay.tv_usec = maxDelayTime % MILLION;
26. }
27.
28. //先执行 socket 的 select 操作,以确定哪些 socket 任务(handler)需要执行。
29. int selectResult = select(fMaxNumSockets,
30. &readSet, &writeSet,&exceptionSet,
31. &tv_timeToDelay);
32.
33. if (selectResult < 0) {
34. //#if defined(__WIN32__) || defined(_WIN32)
35. int err = WSAGetLastError();
36. // For some unknown reason, select() in Windoze sometimes fails with W
SAEINVAL if
37. // it was called with no entries set in "readSet". If this happens, ignore it:
38. if (err == WSAEINVAL && readSet.fd_count == 0) {
39. err = EINTR;
40. // To stop this from happening again, create a dummy socket:
41. int dummySocketNum = socket(AF_INET, SOCK_DGRAM, 0);
42. FD_SET((unsigned) dummySocketNum, &fReadSet);
43. }
44. if (err != EINTR) {
45. //#else
46. // if (errno != EINTR && errno != EAGAIN) {
47. //#endif
48. // Unexpected error - treat this as fatal:
49. //#if !defined(_WIN32_WCE)
50. // perror("BasicTaskScheduler::SingleStep(): select() fails");
51. //#endif
52. internalError();
53. }
54. }
55.
56. // Call the handler function for one readable socket: 57. HandlerIterator iter(*fHandlers);
58. HandlerDescriptor* handler;
59. // To ensure forward progress through the handlers, begin past the last
60. // socket number that we handled:
61. if (fLastHandledSocketNum >= 0) {
62. //找到上次执行的 socket handler 的下一个
63. while ((handler = iter.next()) != NULL) {
64. if (handler->socketNum == fLastHandledSocketNum)
65. break;
66. }
67. if (handler == NULL) {
68. fLastHandledSocketNum = -1;
69. iter.reset(); // start from the beginning instead
70. }
71. }
72.
73. //从找到的 handler 开始,找一个可以执行的 handler,不论其状态是可读,可
写,还是出错,执行之。
74. while ((handler = iter.next()) != NULL) {
75. int sock = handler->socketNum; // alias
76. int resultConditionSet = 0;
77. if (FD_ISSET(sock, &readSet)
78. && FD_ISSET(sock, &fReadSet)/*sanity check*/)
79. resultConditionSet |= SOCKET_READABLE;
80. if (FD_ISSET(sock, &writeSet)
81. && FD_ISSET(sock, &fWriteSet)/*sanity check*/)
82. resultConditionSet |= SOCKET_WRITABLE;
83. if (FD_ISSET(sock, &exceptionSet)
84. && FD_ISSET(sock, &fExceptionSet)/*sanity check*/)
85. resultConditionSet |= SOCKET_EXCEPTION;
86. if ((resultConditionSet & handler->conditionSet)
87. != 0 && handler->handlerProc != NULL) {
88. fLastHandledSocketNum = sock;
89. // Note: we set "fLastHandledSocketNum" before calling the handler,
90. // in case the handler calls "doEventLoop()" reentrantly. 91. (*handler->handlerProc)(handler->clientData, resultConditionSet);
92. break;
93. }
94. }
95.
96. //如果寻找完了依然没有执行任何 handle,则从头再找。
97. if (handler == NULL && fLastHandledSocketNum >= 0) {
98. // We didn't call a handler, but we didn't get to check all of them,
99. // so try again from the beginning:
100. iter.reset();
101. while ((handler = iter.next()) != NULL) {
102. int sock = handler-&g
4000
t;socketNum; // alias
103. int resultConditionSet = 0;
104. if (FD_ISSET(sock, &readSet)&& FD_ISSET(sock, &fReadSet)/*san
ity check*/)
105. resultConditionSet |= SOCKET_READABLE;
106. if (FD_ISSET(sock, &writeSet)&& FD_ISSET(sock, &fWriteSet)/*san
ity check*/)
107. resultConditionSet |= SOCKET_WRITABLE;
108. if (FD_ISSET(sock, &exceptionSet) && FD_ISSET(sock, &fExcepti
onSet)/*sanity check*/)
109. resultConditionSet |= SOCKET_EXCEPTION;
110. if ((resultConditionSet & handler->conditionSet)
111. != 0 && handler->handlerProc != NULL) {
112. fLastHandledSocketNum = sock;
113. // Note: we set "fLastHandledSocketNum" before calling the handl
er,
114. // in case the handler calls "doEventLoop()" reentrantly.
115. (*handler->handlerProc)(handler->clientData, resultConditionSet);
116. break;
117. }
118. }
119. //依然没有找到可执行的 handler。
120. if (handler == NULL)
121. fLastHandledSocketNum = -1; //because we didn't call a handler 122. }
123. //响应事件
124. // Also handle any newly-triggered event
125. // (Note that we do this *after* calling a socket handler,
126. // in case the triggered event handler modifies The set of readable socket
s.)
127. if (fTriggersAwaitingHandling != 0) {
128. if (fTriggersAwaitingHandling == fLastUsedTriggerMask) {
129. // Common-case optimization for a single event trigger:
130. fTriggersAwaitingHandling = 0;
131. if (fTriggeredEventHandlers[fLastUsedTriggerNum] != NULL) {
132. //执行一个事件处理函数
133. (*fTriggeredEventHandlers[fLastUsedTriggerNum])(fTriggeredEv
entClientDatas[fLastUsedTriggerNum]);
134. }
135. } else {
136. // Look for an event trigger that needs handling
137. // (making sure that we make forward progress through all possible t
riggers):
138. unsigned i = fLastUsedTriggerNum;
139. EventTriggerId mask = fLastUsedTriggerMask;
140. do {
141. i = (i + 1) % MAX_NUM_EVENT_TRIGGERS;
142. mask >>= 1;
143. if (mask == 0)
144. mask = 0x80000000;
145. if ((fTriggersAwaitingHandling & mask) != 0) {
146. //执行一个事件响应
147. fTriggersAwaitingHandling &= ~mask;
148. if (fTriggeredEventHandlers[i] != NULL) {
149. (*fTriggeredEventHandlers[i])(fTriggeredEventClientDatas[i])
;
150. }
151. fLastUsedTriggerMask = mask;
152. fLastUsedTriggerNum = i; 153. break;
154. }
155. } while (i != fLastUsedTriggerNum);
156. }
157. }
158. //执行一个最迫切的延迟任务。
159. // Also handle any delayed event that may have come due.
160. fDelayQueue.handleAlarm();
161. }
相关文章推荐
- Andorid中的消息循环机制(一)
- Wpf消息循环之消息传递
- Win编程里的消息循环:pumpmessage、peekMessage
- Chromium on Android: Android在系统Chromium为了实现主消息循环分析
- asyncio文档学习——消息循环EventLoop例子3
- 消息循环的原理
- 工作线程与消息循环
- windows编程(2)深入探讨MFC消息循环和消息泵
- 基于 Linux 和 MiniGUI 的嵌入式系统软件开发指南二——理解消息循环和窗口过程
- Android 之 Looper、MessageQueue、Handler 与消息循环
- live555学习笔记-消息循环
- Windows消息循环之我见
- 深入探讨MFC消息循环和消息泵
- 5 DirectUI消息循环机制
- 互斥锁和条件变量(2)——生产者和消费者(发送消息,循环队列执行)
- Toast和Looper,Handler消息循环机制
- 消息循环
- 父子窗口分属不同消息循环在WinXP和WinCE的差异
- Chromium on Android: Android系统上Chromium主消息循环的实现分析
- Worker线程使用消息循环