History

misc: add a thread pool

To be used by the following commits.

wm4 committed 9 years ago

Commit ec3dd711 parent 7bab24b2 files · +135 −0Browse files

Unified · Split

2 files
  1. misc/thread_pool.c +125 −0
  2. misc/thread_pool.h +10 −0
misc/thread_pool.c+125−0
@@ -0,0 +1,125 @@
1+/*
2+ * This file is part of mpv.
3+ *
4+ * mpv is free software; you can redistribute it and/or
5+ * modify it under the terms of the GNU Lesser General Public
6+ * License as published by the Free Software Foundation; either
7+ * version 2.1 of the License, or (at your option) any later version.
8+ *
9+ * mpv is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU Lesser General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU Lesser General Public
15+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+#include <pthread.h>
19+
20+#include "common/common.h"
21+
22+#include "thread_pool.h"
23+
24+struct work {
25+ void (*fn)(void *ctx);
26+ void *fn_ctx;
27+};
28+
29+struct mp_thread_pool {
30+ pthread_t *threads;
31+ int num_threads;
32+
33+ pthread_mutex_t lock;
34+ pthread_cond_t wakeup;
35+
36+ // --- the following fields are protected by lock
37+ bool terminate;
38+ struct work *work;
39+ int num_work;
40+};
41+
42+static void *worker_thread(void *arg)
43+{
44+ struct mp_thread_pool *pool = arg;
45+
46+ pthread_mutex_lock(&pool->lock);
47+ while (1) {
48+ while (!pool->num_work && !pool->terminate)
49+ pthread_cond_wait(&pool->wakeup, &pool->lock);
50+
51+ if (!pool->num_work && pool->terminate)
52+ break;
53+
54+ assert(pool->num_work > 0);
55+ struct work work = pool->work[pool->num_work - 1];
56+ pool->num_work -= 1;
57+
58+ pthread_mutex_unlock(&pool->lock);
59+ work.fn(work.fn_ctx);
60+ pthread_mutex_lock(&pool->lock);
61+ }
62+ assert(pool->num_work == 0);
63+ pthread_mutex_unlock(&pool->lock);
64+
65+ return NULL;
66+}
67+
68+static void thread_pool_dtor(void *ctx)
69+{
70+ struct mp_thread_pool *pool = ctx;
71+
72+ pthread_mutex_lock(&pool->lock);
73+ pool->terminate = true;
74+ pthread_cond_broadcast(&pool->wakeup);
75+ pthread_mutex_unlock(&pool->lock);
76+
77+ for (int n = 0; n < pool->num_threads; n++)
78+ pthread_join(pool->threads[n], NULL);
79+
80+ assert(pool->num_work == 0);
81+ pthread_cond_destroy(&pool->wakeup);
82+ pthread_mutex_destroy(&pool->lock);
83+}
84+
85+// Create a thread pool with the given number of worker threads. This can return
86+// NULL if the worker threads could not be created. The thread pool can be
87+// destroyed with talloc_free(pool), or indirectly with talloc_free(ta_parent).
88+// If there are still work items on freeing, it will block until all work items
89+// are done, and the threads terminate.
90+struct mp_thread_pool *mp_thread_pool_create(void *ta_parent, int threads)
91+{
92+ assert(threads > 0);
93+
94+ struct mp_thread_pool *pool = talloc_zero(ta_parent, struct mp_thread_pool);
95+ talloc_set_destructor(pool, thread_pool_dtor);
96+
97+ pthread_mutex_init(&pool->lock, NULL);
98+ pthread_cond_init(&pool->wakeup, NULL);
99+
100+ for (int n = 0; n < threads; n++) {
101+ pthread_t thread;
102+ if (pthread_create(&thread, NULL, worker_thread, pool)) {
103+ talloc_free(pool);
104+ return NULL;
105+ }
106+ MP_TARRAY_APPEND(pool, pool->threads, pool->num_threads, thread);
107+ }
108+
109+ return pool;
110+}
111+
112+// Queue a function to be run on a worker thread: fn(fn_ctx)
113+// If no worker thread is currently available, it's appended to a list in memory
114+// with unbounded size. This function always returns immediately.
115+// Concurrent queue calls are allowed, as long as it does not overlap with
116+// pool destruction.
117+void mp_thread_pool_queue(struct mp_thread_pool *pool, void (*fn)(void *ctx),
118+ void *fn_ctx)
119+{
120+ pthread_mutex_lock(&pool->lock);
121+ struct work work = {fn, fn_ctx};
122+ MP_TARRAY_INSERT_AT(pool, pool->work, pool->num_work, 0, work);
123+ pthread_cond_signal(&pool->wakeup);
124+ pthread_mutex_unlock(&pool->lock);
125+}
misc/thread_pool.h+10−0
@@ -0,0 +1,10 @@
1+#ifndef MPV_MP_THREAD_POOL_H
2+#define MPV_MP_THREAD_POOL_H
3+
4+struct mp_thread_pool;
5+
6+struct mp_thread_pool *mp_thread_pool_create(void *ta_parent, int threads);
7+void mp_thread_pool_queue(struct mp_thread_pool *pool, void (*fn)(void *ctx),
8+ void *fn_ctx);
9+
10+#endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t