打印
[应用相关]

ST学习笔记

[复制链接]
手机看帖
扫描二维码
随时随地手机跟帖
21
花间一壶酒sd|  楼主 | 2021-2-20 22:23 | 只看该作者 回帖奖励 |倒序浏览
25. /* Continue the cleanup */

26. st_cond_destroy(thread->term);

27. thread->term = NULL;

28. }

29.

使用特权

评论回复
22
花间一壶酒sd|  楼主 | 2021-2-20 22:24 | 只看该作者
30. if (!(thread->flags & _ST_FL_PRIMORDIAL))

31. _st_stack_free(thread->stack);

32.

33. /* 切换上下文 */

34. _ST_SWITCH_CONTEXT(thread);

35. /* Not going to land here */

36. /* 此处不会执行到,详见_ST_SWITCH_CONTEXT注释 */

37. }

使用特权

评论回复
23
花间一壶酒sd|  楼主 | 2021-2-20 22:25 | 只看该作者
4)_ST_SWITCH_CONTEXT

1. /*

2.  * 切换上下文,即正在执行的线程主动让出CPU

3.  * 1)保存当前线程上下文

4.  * 2)调用_st_vp_schedule选择下一个可执行的线程

5.  */

6. #define _ST_SWITCH_CONTEXT(_thread)       \

7.     ST_BEGIN_MACRO                        \

8.     ST_SWITCH_OUT_CB(_thread);            \/* ST_SWITCH_OUT_CB线程切出回调函数,默认为NULL,用户可以通过st_set_switch_out_cb设置 */

9.     if (!MD_SETJMP((_thread)->context)) { \/* 保存当前线程上下文 */

10.       _st_vp_schedule();                  \/* 1、如果是上下文切出,调用_st_vp_schedule

11.  * 2、如果是上下文切入,不会调用。对于st_thread_exit,上下文切出后thread结构被释放

12.  * 不会再次切入

13. */

14.     }                                     \

15.     ST_DEBUG_ITERATE_THREADS();           \

16.     ST_SWITCH_IN_CB(_thread);             \ /* ST_SWITCH_IN_CB线程切入回调函数,默认为NULL,用户可以通过st_set_switch_in_cb设置 */

17.     ST_END_MACRO

使用特权

评论回复
24
花间一壶酒sd|  楼主 | 2021-2-20 22:28 | 只看该作者
5)_st_vp_schedule

1. /*

2.  * ST的调度程序

3. */

4. void _st_vp_schedule(void)

5. {

6. _st_thread_t *thread;

7.

使用特权

评论回复
25
花间一壶酒sd|  楼主 | 2021-2-20 22:30 | 只看该作者
8. /* 选择下一个运行的线程 */

9. if (_ST_RUNQ.next != &_ST_RUNQ) {

10. /* 从RUNQ选择(RR调度)待运行线程 */

11. thread = _ST_THREAD_PTR(_ST_RUNQ.next);

12. _ST_DEL_RUNQ(thread);

13. } else {

14. /* 如果没有待运行线程,切换到idle线程执行

15.  * 实际上是调用_st_idle_thread_start将IO Ready或者wait超时的线程加入待运行队列

16.  * 然后idle线程切换上下文,让渡CPU。参见_st_idle_thread_start注释

17.     */

18. thread = _st_this_vp.idle_thread;

19. }

20. ST_ASSERT(thread->state == _ST_ST_RUNNABLE);

21.

使用特权

评论回复
26
花间一壶酒sd|  楼主 | 2021-2-20 22:32 | 只看该作者
22. /* 通过longjmp恢复线程的上下文

23.  * #define _ST_RESTORE_CONTEXT(_thread)   \

24.  * ST_BEGIN_MACRO                     \

25.  * _ST_SET_CURRENT_THREAD(_thread);   \

26.  * MD_LONGJMP((_thread)->context, 1); \

27.  * ST_END_MACRO

28. */

29. thread->state = _ST_ST_RUNNING;

30. _ST_RESTORE_CONTEXT(thread);

31. }

使用特权

评论回复
27
花间一壶酒sd|  楼主 | 2021-2-20 22:33 | 只看该作者
6)_st_idle_thread_start

1. /*

2.  * idle线程循环调度函数,

3.  * 仅当RUNQ上无可运行线程时,idle线程才会被调度

4.  * idle线程功能:

5.  * 1)当无活跃线程时(活跃线程不包括idle线程),退出整个执行程序

6.  * 2)当有活跃线程

7. i)调用_st_epoll_dispatch将IO Ready线程设置为可运行状态,加入到RUNQ

8.  *ii)调用_st_vp_check_clock将timewait超时的线程设置为可运行状态,加入到RUNQ

9.  *  iii)切换上下文,将CPU让渡给活跃线程

10. */

11. void *_st_idle_thread_start(void *arg)

12. {

使用特权

评论回复
28
花间一壶酒sd|  楼主 | 2021-2-20 22:35 | 只看该作者
13. _st_thread_t *me = _ST_CURRENT_THREAD();

14. /*

15.  * 检查活跃线程计数,如果无活跃线程退出整个程序

16.  * 这也是为何创建微线程时活跃计数加一,线程退出时活跃计数减一的原因

17.  */

18. while (_st_active_count > 0) {

19. /* 实际上是调用_st_epoll_dispatch(或者_st_select_dispatch等其他多路复用函数)将之前因为IO等待换出的线程再次加入运行队列 */

20. _ST_VP_IDLE();

21.

使用特权

评论回复
29
花间一壶酒sd|  楼主 | 2021-2-20 22:37 | 只看该作者
22. /* 唤醒timewait的线程 */

23. _st_vp_check_clock();

24.

25. me->state = _ST_ST_RUNNABLE;

26. _ST_SWITCH_CONTEXT(me);

27. }

28.

使用特权

评论回复
30
花间一壶酒sd|  楼主 | 2021-2-20 22:38 | 只看该作者
29. /* No more threads */

30. exit(0);

31.

32. /* NOTREACHED */

33. return NULL;

34. }

使用特权

评论回复
31
花间一壶酒sd|  楼主 | 2021-2-20 22:38 | 只看该作者
7)_st_idle_thread_start

1. /*

2.  * ST初始化函数

3.  * 1) 完成全局数据的初始化,包括:

4. i) 多路复用机制的选择(默认epoll)

5. ii)_st_io_init信号SIGPIPE的屏蔽,rlimit参数的设置

6. iii)_st_vp结构初始化,以及三个线程队列(RUNQ、IOQ、ZOMBIEQ)的初始化

7.    2) 通过st_thread_create创建idle线程

8.    3) 创建初始(primordial)线程,不是通过st_thread_create创建,初始线程仅有_st_thread_t结构,并没有单独分配线程栈,而是直接使用物理线程的线程栈

9. */

10. int st_init(void)

11. {

12. _st_thread_t *thread;

13.

使用特权

评论回复
32
花间一壶酒sd|  楼主 | 2021-2-20 22:40 | 只看该作者
14. if (_st_active_count) {

15. /* Already initialized */

16. return 0;

17. }

18.

使用特权

评论回复
33
花间一壶酒sd|  楼主 | 2021-2-20 22:41 | 只看该作者
19. /* We can ignore return value here */

20. st_set_eventsys(ST_EVENTSYS_DEFAULT);

21.

22. if (_st_io_init() < 0)

23. return -1;

24.

25. memset(&_st_this_vp, 0, sizeof(_st_vp_t));

26.

使用特权

评论回复
34
花间一壶酒sd|  楼主 | 2021-2-20 22:44 | 只看该作者
27. ST_INIT_CLIST(&_ST_RUNQ);

28. ST_INIT_CLIST(&_ST_IOQ);

29. ST_INIT_CLIST(&_ST_ZOMBIEQ);

30.

31. if ((*_st_eventsys->init)() < 0)

32. return -1;

33.

使用特权

评论回复
35
花间一壶酒sd|  楼主 | 2021-2-20 22:47 | 只看该作者
34. _st_this_vp.pagesize = getpagesize();

35. _st_this_vp.last_clock = st_utime();

36.

37. /*

38.  * 创建idle线程,入口函数为_st_idle_thread_start

39. */

40. _st_this_vp.idle_thread = st_thread_create(_st_idle_thread_start, NULL, 0, 0);

41. if (!_st_this_vp.idle_thread)

42. return -1;

43. _st_this_vp.idle_thread->flags = _ST_FL_IDLE_THREAD;

44. _st_active_count--;/* idle线程不作为活跃线程 */

45. _ST_DEL_RUNQ(_st_this_vp.idle_thread);/* idle线程不放到RUNQ被调度,而是当RUNQ为空时由_st_vp_schedule调度 */

46.

使用特权

评论回复
36
花间一壶酒sd|  楼主 | 2021-2-20 22:51 | 只看该作者
47. /*

48.  * 创建初始线程

49. */

50. thread = (_st_thread_t *) calloc(1, sizeof(_st_thread_t) + (ST_KEYS_MAX * sizeof(void *)));

51. if (!thread)

52. return -1;

53. thread->private_data = (void **) (thread + 1);

54. thread->state = _ST_ST_RUNNING;

55. thread->flags = _ST_FL_PRIMORDIAL;

56. _ST_SET_CURRENT_THREAD(thread);/* 将初始线程设置为current线程,此时初始线程控制CPU */

57. _st_active_count++;/* 初始线程作为活跃进程,当初始线程不退出时,_st_idle_thread_start不会退出 */

58.

使用特权

评论回复
37
花间一壶酒sd|  楼主 | 2021-2-20 22:54 | 只看该作者
59. return 0;

60. /*

61.  * ST初始化后,CPU仍有物理线程(初始线程)控制,

62.  * 如果想切换至其他ST线程,需要手动调用会执行上下文切换的函数。如:st_thread_exit、st_poll或st_usleep等

63. */

64. }

使用特权

评论回复
38
花间一壶酒sd|  楼主 | 2021-2-20 22:55 | 只看该作者
四、ST线程的生命周期
ST执行流程。

第一个阶段: st_init创建idle线程和创建初始(priordial)线程,此时_st_active_count是1,物理线程(即初始线程)控制CPU。

第二个阶段:用户创建线程。调用st_thread_create时,会把_st_active_count递增,并且加入RUNQ。

第三个阶段:初始线程切换,将CPU控制权交给ST。也就是初始线程,做完st_init和创建其他线程后,这个时候还没有任何的线程切换。初始线程需要将控制权切换给st,可以调用st_sleep循环和休眠,或者调用st_thread_exit(NULL)等待其他线程结束。如果该阶段物理线程不进行切换,ST将无法获取控制权,程序会直接返回。

使用特权

评论回复
39
花间一壶酒sd|  楼主 | 2021-2-20 22:55 | 只看该作者
下面通过简单的ST例子,说明编写ST程序的流程。复杂的例子见源代码中proxy和server的实现。

1. #include <stdio.h>

2. #include "st.h"

3. void *do_print(void *str)

4. {

5.     fprintf(stdout, "arg is %s\n", (char *)str);

6.     return NULL;

7. }

8.

使用特权

评论回复
40
花间一壶酒sd|  楼主 | 2021-2-20 22:56 | 只看该作者
9. int main(int argc, char *argv[])

10. {

11.     int i;

12.     if (argc < 2) {

13.         fprintf(stderr, "Usage: %s args ...\n", argv[0]);

14.         exit(1);

15.     }

16.     // 初始化ST

17.     if (st_init() < 0) {

18.         exit(1);

19.     }

20.   //根据参数个数创建微线程

21.     for (i = 1; i < argc; i++) {

22.         if (st_thread_create(do_print, argv[i], 0, 0) == NULL) {

23.             exit(1);

24.         }

25.     }

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则