Glib学习(12) 线程池 Thread Pools

妖狐艹你老母 2022-05-31 01:41 423阅读 0赞

glib源码下载:http://ftp.gnome.org/pub/gnome/sources/glib/

glib帮助文档:https://developer.gnome.org/glib/

首先将翻译贴上

描述

有时候,你希望异步分出工作的执行,并继续在你自己的线程中工作。如果这种情况经常发生,每次启动和销毁线程的开销可能太高。在这种情况下,重用已经启动的线程似乎是一个好主意。确实如此,但是实施这个过程可能很乏味且容易出错。
因此,为了您的方便,GLib提供了线程池。另外一个好处是,当你使用GLib时,线程可以在程序的不同子系统之间共享。
要创建一个新的线程池,可以使用g_thread_pool_new()。它被g_thread_pool_free()销毁。
如果要在线程池中执行某个任务,请调用g_thread_pool_push()。
要获得当前正在运行的线程数,请调用g_thread_pool_get_num_threads()。要获得尚未处理的任务的数量,请调用g_thread_pool_unprocessed()。要控制线程池的最大线程数,可以使用g_thread_pool_get_max_threads()和g_thread_pool_set_max_threads()。
最后,您可以控制未使用的线程的数量,这些线程由GLib保存以供将来使用。可以使用g_thread_pool_get_num_unused_threads()获取当前数量。最大数量可以由g_thread_pool_get_max_unused_threads()和g_thread_pool_set_max_unused_threads()来控制。所有当前未使用的线程都可以通过调用g_thread_pool_stop_unused_threads()来停止。

g_thread_pool_new ()

这个函数创建一个新的线程池。

无论何时调用g_thread_pool_push(),都会创建一个新的线程,或者重用一个未使用的线程。 线程池最多可以同时运行max_threads线程。 max_threads = -1允许为此线程池创建无限的线程。 新创建或重用的线程现在用两个参数执行函数func。 第一个是g_thread_pool_push()的参数,第二个是user_data。
独占参数确定线程池是否拥有所有线程的独占权或与其他线程池共享它们。 如果exclusive为TRUE,则max_threads线程立即启动,它们将专门为该线程池运行,直到被g_thread_pool_free()销毁。 如果exclusive是FALSE,则在需要时创建线程,并在所有非独占线程池之间共享。 这意味着max_threads对于独占线程池不可能是-1。 此外,独占线程池不受g_thread_pool_set_max_idle_time()影响,因为它们的线程永远不会被视为空闲并返回到全局池。
error 可以是NULL来忽略错误,或者是非NULL来报告错误。 只有将exclusive设置为TRUE时才会出现错误,并且不能创建所有的max_thread线程。 请参阅GThreadError,了解可能发生的错误。 请注意,即使发生错误,也会返回有效的GThreadPool。

参数
func
一个在新线程池的线程中执行的函数
user_data
用户数据每次被调用时都会传递给func
max_threads
在新的线程池中同时执行的最大线程数,-1表示没有限制
exclusive
这个线程池应该是独占的吗?
error
返回错误的位置,或NULL

返回
新的GThreadPool

g_thread_pool_push ()

将数据插入池中要执行的任务列表。

当前正在运行的线程的数量低于最大允许的线程数时,将使用给g_thread_pool_new()的属性启动(或重用)一个新的线程。 否则,数据将保留在队列中,直到此池中的线程完成其之前的任务并处理数据。
error 可以是NULL来忽略错误,或者是非NULL来报告错误。 只有在无法创建新线程时才会发生错误。 在这种情况下,数据只是附加到要做的工作队列中。
在版本2.32之前,此函数没有返回成功状态。

参数
pool
一个GThreadPool
data
池的新任务
error
返回错误的位置,或NULL

返回
成功为TRUE,发生错误时为FALSE

g_thread_pool_set_max_threads ()

设置池的最大允许线程数。 值-1意味着线程的最大数目是无限的。 如果池是独占线程池,则不允许将最大线程数设置为-1。
将max_threads设置为0意味着停止池的所有工作。 它被有效地冻结,直到max_threads再次被设置为非零值。
调用func时线程永远不会被终止,就像g_thread_pool_new()所提供的那样。 相反,最大线程数只对g_thread_pool_push()中的新线程分配有效。 只要当前正在运行的线程数量小于最大数量,就会分配一个新的线程。
error 可以是NULL来忽略错误,或者是非NULL来报告错误。 只有在无法创建新线程时才会发生错误。
在版本2.32之前,此函数没有返回成功状态。

参数
pool
一个GThreadPool
max_threads
池的最大线程数,或者-1表示无限制
error
返回错误的位置,或NULL

返回
成功为TRUE,发生错误时为FALSE

g_thread_pool_get_max_threads ()

返回池的最大线程数。

参数
pool
一个GThreadPool

返回
线程的最大数量

g_thread_pool_get_num_threads ()

返回当前在池中运行的线程数。

参数
pool
一个GThreadPool

返回
当前正在运行的线程的数量

g_thread_pool_unprocessed ()

返回池中尚未处理的任务数。

参数
pool
一个GThreadPool

返回
未处理的任务数量

g_thread_pool_free ()

释放为池分配的所有资源。
如果immediate为TRUE,则不会为池处理新的任务。 否则,在最后一个任务被处理之前,池没有被释放。 但请注意,正在处理的任务,线程不会中断。 也就是说,所有仍在运行的线程都可以在释放池之前完成任务。
如果wait_为TRUE,则在所有要处理的任务(取决于immediate,无论是全部还是仅当前正在运行)都完成之前,函数不会返回。 否则,函数立即返回。
调用这个函数池之后就不能再使用了。

参数
pool
一个GThreadPool
immediate
应该立即关闭吗?
wait_
该函数是否应该等待所有的任务完成?

g_thread_pool_set_max_unused_threads ()

将未使用线程的最大数量设置为max_threads。 如果max_threads为-1,则不会对未使用的线程数量施加任何限制。
默认值是2。

参数
max_threads
未使用线程的最大数量

g_thread_pool_get_max_unused_threads ()

返回未使用线程的最大允许数量。

返回
未使用线程的最大数量

g_thread_pool_get_num_unused_threads ()

返回当前未使用线程的数量。

返回
当前未使用的线程的数量

g_thread_pool_stop_unused_threads ()

停止当前所有未使用的线程。 这不会更改未使用的线程的最大数量。 这个功能可以用来定期停止所有未使用的线程,例如 来自g_timeout_add()。

g_thread_pool_set_sort_function ()

设置用于排序任务列表的函数。 这允许按照func确定的优先级处理任务,而不仅仅是按照将其添加到池中的顺序处理。
请注意,如果最大线程数大于1,则执行线程的顺序不能保证100%。 线程由操作系统调度并随机执行。 不能认为线程按照它们创建的顺序执行。

参数
pool
一个GThreadPool
func
GCompareDataFunc用来排序任务列表。 这个函数传递两个任务。 它应该返回0,如果它们的处理顺序无关紧要,如果第一个任务应该在第二个任务之前处理,则返回负值;如果第二个任务应该先处理,则返回正值。
user_data
用户数据传递给func
从:2.10

g_thread_pool_set_max_idle_time ()

这个函数将设置一个在新池中等待新任务的线程在停止之前可以空闲的最大时间间隔。 这个函数类似于在正常超时时调用g_thread_pool_stop_unused_threads(),除了这是在每个线程的基础上完成的。
通过设置间隔为0,空闲线程不会停止。
默认值是15000(15秒)。

参数
interval
线程可以空闲的最大间隔(以毫秒为单位)
从:2.10

g_thread_pool_get_max_idle_time ()

此函数将返回线程在线程池中等待新任务的最大间隔,然后才能停止。
如果这个函数返回0,那么在线程池中等待新工作的线程不会停止。

返回
停止线程之前等待线程池中新任务的最大间隔(毫秒)
从:2.10

g_thread_pool_move_to_front ()

将项目移动到未处理项目的队列的前面,以便接下来处理。

参数
pool
一个GThreadPool
data
池中未处理的项目

返回
如果找到并移动了该项目,则为TRUE
从:2.46

类型和值

struct GThreadPool

struct GThreadPool {
GFunc func;
gpointer user_data;
gboolean exclusive;
};
GThreadPool结构表示一个线程池。 它有三个公共只读成员,但底层结构更大,所以你不能复制这个结构。

成员

GFunc func;
在这个池的线程中执行的函数

gpointer user_data;
该池的线程的用户数据

gboolean exclusive;
这个池独占所有的线程

然后是提供一个几乎使用了全部函数的例程,可以直接编译运行的。其中的注释掉的函数只是与相近的函数互补的,可以解注查看效果。

  1. #include <glib.h>
  2. #include <glib/gprintf.h>
  3. #include <unistd.h>
  4. #include <sys/syscall.h>
  5. //#include <pthread.h>
  6. //用来排序任务列表
  7. gint compare_data (gconstpointer a, gconstpointer b, gpointer user_data)
  8. {
  9. if(user_data == NULL)//从小到大
  10. {
  11. if(*((gint *)a) > *((gint *)b))
  12. return 1;
  13. else
  14. return -1;
  15. }
  16. else//从大到小
  17. {
  18. if(*((gint *)a) < *((gint *)b))
  19. return 1;
  20. else
  21. return -1;
  22. }
  23. }
  24. //线程执行函数,进入后打印数据,并睡眠5秒
  25. void thread_execute (gpointer data, gpointer user_data)
  26. {
  27. g_printf("thread_execute %ld in\n", syscall(__NR_gettid));
  28. g_printf("thread_execute %ld data is : %d\n", syscall(__NR_gettid), *((gint *)data));
  29. g_usleep (5000000);
  30. g_printf("thread_execute %ld out\n", syscall(__NR_gettid));
  31. }
  32. gint data[10];
  33. int main(int argc, char **argv)
  34. {
  35. g_printf ("main in\n");
  36. gint count;
  37. GError *gerr = NULL;
  38. GThreadPool *gpool = NULL;
  39. //最大同时执行2个线程,由于exclusive设置为FALSE,所以不会有错误发生,error被设置为NULL
  40. gpool = g_thread_pool_new (thread_execute, NULL, 2, FALSE, NULL);
  41. g_printf("thread pool max threads is %d\n", g_thread_pool_get_max_threads (gpool));
  42. g_printf("thread pool num threads is %d\n", g_thread_pool_get_num_threads (gpool));
  43. //线程池中最大允许线程数3个
  44. if(!g_thread_pool_set_max_threads (gpool, 3, &gerr))
  45. g_printf("g_thread_pool_set_max_threads is error: %s\n", gerr->message);
  46. g_printf("thread pool max threads is %d\n", g_thread_pool_get_max_threads (gpool));
  47. g_printf("thread pool num threads is %d\n", g_thread_pool_get_num_threads (gpool));
  48. /**
  49. * 实际线程池中最多有3个线程同时运行
  50. */
  51. for (count = 0; count < (sizeof(data)/sizeof(gint)); count++)
  52. {
  53. data[count] = count;
  54. g_thread_pool_push(gpool, (gpointer)(&(data[count])), &gerr);
  55. if(gerr != NULL)
  56. {
  57. g_printf("g_thread_pool_push is error: %s\n", gerr->message);
  58. }
  59. }
  60. g_usleep (100000);
  61. g_printf("thread pool num threads is %d\n", g_thread_pool_get_num_threads (gpool));
  62. g_printf("thread pool unprocessed num is %d\n", g_thread_pool_unprocessed (gpool));
  63. g_printf("thread pool num unused threads is %d\n", g_thread_pool_get_num_unused_threads ());
  64. //插入优先级高的新任务
  65. if(g_thread_pool_move_to_front (gpool, (gpointer)(&(data[9]))))
  66. g_printf("g_thread_pool_move_to_front is 9\n");
  67. //立即释放,不继续执行任务队列
  68. //g_thread_pool_free (gpool, TRUE, TRUE);
  69. //等待任务队列中的任务全部执行完成
  70. g_thread_pool_free (gpool, FALSE, TRUE);
  71. g_printf("thread pool num unused threads is %d\n", g_thread_pool_get_num_unused_threads ());
  72. //设置最大空闲时间2s
  73. g_thread_pool_set_max_idle_time (2000);
  74. g_usleep (5000000);
  75. g_printf("thread pool num unused threads is %d\n", g_thread_pool_get_num_unused_threads ());
  76. //最大同时执行1个线程,由于exclusive设置为FALSE,所以不会有错误发生,error被设置为NULL
  77. gpool = g_thread_pool_new (thread_execute, NULL, 1, FALSE, NULL);
  78. /**
  79. * 实际线程池中最多有3个线程同时运行
  80. */
  81. for (count = 0; count < (sizeof(data)/sizeof(gint)); count++)
  82. {
  83. data[count] = count;
  84. g_thread_pool_push(gpool, (gpointer)(&(data[count])), &gerr);
  85. if(gerr != NULL)
  86. {
  87. g_printf("g_thread_pool_push is error: %s\n", gerr->message);
  88. }
  89. }
  90. //从小到大
  91. //g_thread_pool_set_sort_function (gpool, compare_data, NULL);
  92. //从大到小
  93. g_thread_pool_set_sort_function (gpool, compare_data, (gpointer)(1));
  94. //等待任务队列中的任务全部执行完成
  95. g_thread_pool_free (gpool, FALSE, TRUE);
  96. //while(1);
  97. g_printf ("main out\n");
  98. return 0;
  99. }

有时候我们不仅仅是把数据传给任务队列进行处理,可能我们还要任务队列执行不同的函数动作,下面的例程就是将函数传递给任务队列的例程。

  1. #include <glib.h>
  2. #include <glib/gprintf.h>
  3. #include <unistd.h>
  4. #include <sys/syscall.h>
  5. typedef gint (*thread_func) (gpointer data);
  6. struct thread_func_data {
  7. thread_func func;
  8. gpointer data;
  9. };
  10. struct add_data {
  11. gint a;
  12. gint b;
  13. };
  14. struct square_data {
  15. gint a;
  16. };
  17. struct mix_data {
  18. gint a;
  19. gint b;
  20. gint c;
  21. };
  22. //add
  23. gint add_func (gpointer data)
  24. {
  25. struct add_data *arg = (struct add_data *)data;
  26. gint c;
  27. c = arg->a + arg->b;
  28. g_printf("add_func: %d+%d = %d\n", arg->a, arg->b, c);
  29. g_usleep (3000000);
  30. g_free (data);
  31. return c;
  32. }
  33. //square
  34. gint square_func (gpointer data)
  35. {
  36. struct square_data *arg = (struct square_data *)data;
  37. gint c;
  38. c = arg->a * arg->a;
  39. g_printf("square_data: %d^2 = %d\n", arg->a, c);
  40. g_usleep (5000000);
  41. g_free (data);
  42. return c;
  43. }
  44. //Mixed operations
  45. gint mix_func (gpointer data)
  46. {
  47. struct mix_data *arg = (struct mix_data *)data;
  48. gint c;
  49. c = arg->a * arg->b + arg->c;
  50. g_printf("mix_data: %d*%d+%d = %d\n", arg->a, arg->b, arg->c, c);
  51. g_usleep (7000000);
  52. g_free (data);
  53. return c;
  54. }
  55. //线程执行函数,进入后打印数据,并睡眠5秒
  56. void thread_execute (gpointer data, gpointer user_data)
  57. {
  58. g_printf("thread_execute %ld in\n", syscall(__NR_gettid));
  59. struct thread_func_data *arg = (struct thread_func_data *)data;
  60. (*(arg->func))(arg->data);
  61. g_free (data);
  62. g_printf("thread_execute %ld out\n", syscall(__NR_gettid));
  63. }
  64. gint data[10];
  65. int main(int argc, char **argv)
  66. {
  67. g_printf ("main in\n");
  68. GError *gerr = NULL;
  69. GThreadPool *gpool = NULL;
  70. //最大同时执行1个线程,由于exclusive设置为FALSE,所以不会有错误发生,error被设置为NULL
  71. gpool = g_thread_pool_new (thread_execute, NULL, 1, FALSE, NULL);
  72. struct add_data *ad = (struct add_data *)g_malloc (sizeof(struct add_data));
  73. ad->a = 5; ad->b = 6;
  74. struct thread_func_data *tfd_a = (struct thread_func_data *)g_malloc (sizeof(struct thread_func_data));
  75. tfd_a->func = add_func; tfd_a->data = ad;
  76. g_thread_pool_push(gpool, (gpointer)(tfd_a), &gerr);
  77. if(gerr != NULL)
  78. {
  79. g_printf("g_thread_pool_push is error: %s\n", gerr->message);
  80. }
  81. struct square_data *sd = (struct square_data *)g_malloc (sizeof(struct square_data));
  82. sd->a = 77;
  83. struct thread_func_data *tfd_s = (struct thread_func_data *)g_malloc (sizeof(struct thread_func_data));
  84. tfd_s->func = square_func; tfd_s->data = sd;
  85. g_thread_pool_push(gpool, (gpointer)(tfd_s), &gerr);
  86. if(gerr != NULL)
  87. {
  88. g_printf("g_thread_pool_push is error: %s\n", gerr->message);
  89. }
  90. struct mix_data *md = (struct mix_data *)g_malloc (sizeof(struct mix_data));
  91. md->a = 2; md->b = 3; md->c = 4;
  92. struct thread_func_data *tfd_m = (struct thread_func_data *)g_malloc (sizeof(struct thread_func_data));
  93. tfd_m->func = mix_func; tfd_m->data = md;
  94. g_thread_pool_push(gpool, (gpointer)(tfd_m), &gerr);
  95. if(gerr != NULL)
  96. {
  97. g_printf("g_thread_pool_push is error: %s\n", gerr->message);
  98. }
  99. //等待任务队列中的任务全部执行完成
  100. g_thread_pool_free (gpool, FALSE, TRUE);
  101. //while(1);
  102. g_printf ("main out\n");
  103. return 0;
  104. }

发表评论

表情:
评论列表 (有 0 条评论,423人围观)

还没有评论,来说两句吧...

相关阅读