Skip to content

Commit 7582cc3

Browse files
committedJun 1, 2017
c_sync: using std::thread;
Signed-off-by: Benn Snyder <[email protected]>
1 parent e59e4ef commit 7582cc3

File tree

2 files changed

+134
-113
lines changed

2 files changed

+134
-113
lines changed
 

‎wrappers/c_sync/CMakeLists.txt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
# C Synchronous Interface
33
######################################################################################
44

5-
set(THREADS_USE_PTHREADS_WIN32 true)
5+
cmake_minimum_required(VERSION 3.5)
6+
67
find_package(Threads REQUIRED)
7-
include_directories(${THREADS_PTHREADS_INCLUDE_DIR})
8+
list(APPEND CompileFeatures "cxx_alias_templates" "cxx_nullptr")
89

9-
add_library (freenect_sync SHARED libfreenect_sync.c)
10-
add_library (freenect_sync_static STATIC libfreenect_sync.c)
10+
add_library(freenect_sync SHARED libfreenect_sync.cpp)
11+
add_library(freenect_sync_static STATIC libfreenect_sync.cpp)
12+
target_compile_features(freenect_sync PRIVATE ${CompileFeatures})
13+
target_compile_features(freenect_sync_static PRIVATE ${CompileFeatures})
1114
set_target_properties (freenect_sync_static PROPERTIES OUTPUT_NAME freenect_sync)
1215

1316
set_target_properties (freenect_sync PROPERTIES

‎wrappers/c_sync/libfreenect_sync.c renamed to ‎wrappers/c_sync/libfreenect_sync.cpp

Lines changed: 127 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,37 @@
2323
* Binary distributions must follow the binary distribution requirements of
2424
* either License.
2525
*/
26-
#include <stdio.h>
27-
#include <pthread.h>
28-
#include <string.h>
29-
#include <stdlib.h>
30-
#include <assert.h>
26+
#include <cassert>
27+
#include <condition_variable>
28+
#include <iostream>
29+
#include <thread>
30+
#include <mutex>
3131
#include "libfreenect_registration.h"
3232
#include "libfreenect_sync.h"
3333

34+
using std::cerr;
35+
using std::endl;
36+
using Mutex = std::mutex;
37+
using UniqueLock = std::unique_lock<Mutex>;
38+
using LockGuard = std::lock_guard<Mutex>;
39+
using ConditionVariable = std::condition_variable;
40+
using Thread = std::thread;
41+
42+
namespace
43+
{
44+
void FN_WARN_INVALID_INDEX(const int index)
45+
{
46+
cerr << "Error: Invalid index [" << index << "]" << endl;
47+
}
48+
}
49+
50+
3451
typedef struct buffer_ring {
35-
pthread_mutex_t lock;
36-
pthread_cond_t cb_cond;
52+
Mutex mutex;
53+
ConditionVariable cb_cond;
3754
void *bufs[3];
3855
uint32_t timestamp;
39-
int valid; // True if middle buffer is valid
56+
bool valid; // True if middle buffer is valid
4057
int fmt;
4158
int res;
4259
} buffer_ring_t;
@@ -47,102 +64,113 @@ typedef struct sync_kinect {
4764
buffer_ring_t depth;
4865
} sync_kinect_t;
4966

67+
struct AutomaticShutdownThread : public Thread
68+
{
69+
using Thread::thread;
70+
71+
virtual ~AutomaticShutdownThread()
72+
{
73+
freenect_sync_stop();
74+
}
75+
76+
AutomaticShutdownThread& operator=(Thread&& other)
77+
{
78+
Thread::operator=(std::move(other));
79+
return *this;
80+
}
81+
};
82+
5083
typedef int (*set_buffer_t)(freenect_device *dev, void *buf);
5184

5285
#define MAX_KINECTS 64
5386
static sync_kinect_t *kinects[MAX_KINECTS] = { 0 };
5487
static freenect_context *ctx;
55-
static int thread_running = 0;
56-
static pthread_t thread;
57-
static pthread_mutex_t runloop_lock = PTHREAD_MUTEX_INITIALIZER;
88+
static bool thread_running = false;
89+
static AutomaticShutdownThread thread;
90+
static Mutex runloop_mutex;
5891
static int pending_runloop_tasks = 0;
59-
static pthread_mutex_t pending_runloop_tasks_lock = PTHREAD_MUTEX_INITIALIZER;
60-
static pthread_cond_t pending_runloop_tasks_cond = PTHREAD_COND_INITIALIZER;
61-
62-
/* Locking Convention
63-
Rules:
64-
- if you need more than one lock on a line, get them from left to right
65-
- do not mix locks on different lines
66-
- if you need to change the lock rules, make sure you check everything and update this
67-
Lock Families:
68-
- pending_runloop_tasks_lock
69-
- runloop_lock, buffer_ring_t.lock (NOTE: You may only have one)
92+
static Mutex pending_runloop_tasks_mutex;
93+
static ConditionVariable pending_runloop_tasks_cond;
94+
95+
/* Lock Families:
96+
- pending_runloop_tasks_mutex
97+
- runloop_mutex, buffer_ring_t.mutex (NOTE: You may only have one)
7098
*/
7199

72100
static int alloc_buffer_ring_video(freenect_resolution res, freenect_video_format fmt, buffer_ring_t *buf)
73101
{
74-
int sz, i;
102+
int size;
75103
switch (fmt) {
76104
case FREENECT_VIDEO_RGB:
77105
case FREENECT_VIDEO_BAYER:
78106
case FREENECT_VIDEO_IR_8BIT:
79107
case FREENECT_VIDEO_IR_10BIT:
80108
case FREENECT_VIDEO_IR_10BIT_PACKED:
81-
sz = freenect_find_video_mode(res, fmt).bytes;
109+
size = freenect_find_video_mode(res, fmt).bytes;
82110
break;
83111
default:
84-
printf("Invalid video format %d\n", fmt);
112+
cerr << "Invalid video format " << fmt << endl;
85113
return -1;
86114
}
87-
for (i = 0; i < 3; ++i)
88-
buf->bufs[i] = malloc(sz);
115+
for (short i = 0; i < 3; ++i) {
116+
buf->bufs[i] = malloc(size);
117+
}
89118
buf->timestamp = 0;
90-
buf->valid = 0;
119+
buf->valid = false;
91120
buf->fmt = fmt;
92121
buf->res = res;
93122
return 0;
94123
}
95124

96125
static int alloc_buffer_ring_depth(freenect_resolution res, freenect_depth_format fmt, buffer_ring_t *buf)
97126
{
98-
int sz, i;
127+
int size;
99128
switch (fmt) {
100129
case FREENECT_DEPTH_11BIT:
101130
case FREENECT_DEPTH_10BIT:
102131
case FREENECT_DEPTH_11BIT_PACKED:
103132
case FREENECT_DEPTH_10BIT_PACKED:
104133
case FREENECT_DEPTH_REGISTERED:
105134
case FREENECT_DEPTH_MM:
106-
sz = freenect_find_depth_mode(res, fmt).bytes;
135+
size = freenect_find_depth_mode(res, fmt).bytes;
107136
break;
108137
default:
109-
printf("Invalid depth format %d\n", fmt);
138+
cerr << "Invalid depth format " << fmt << endl;
110139
return -1;
111140
}
112-
for (i = 0; i < 3; ++i)
113-
buf->bufs[i] = malloc(sz);
141+
for (short i = 0; i < 3; ++i) {
142+
buf->bufs[i] = malloc(size);
143+
}
114144
buf->timestamp = 0;
115-
buf->valid = 0;
145+
buf->valid = false;
116146
buf->fmt = fmt;
117147
buf->res = res;
118148
return 0;
119149
}
120150

121151
static void free_buffer_ring(buffer_ring_t *buf)
122152
{
123-
int i;
124-
for (i = 0; i < 3; ++i) {
153+
for (short i = 0; i < 3; ++i) {
125154
free(buf->bufs[i]);
126-
buf->bufs[i] = NULL;
155+
buf->bufs[i] = nullptr;
127156
}
128157
buf->timestamp = 0;
129-
buf->valid = 0;
158+
buf->valid = false;
130159
buf->fmt = -1;
131160
buf->res = -1;
132161
}
133162

134163
static void producer_cb_inner(freenect_device *dev, void *data, uint32_t timestamp, buffer_ring_t *buf, set_buffer_t set_buffer)
135164
{
136-
pthread_mutex_lock(&buf->lock);
165+
UniqueLock buffer_lock(buf->mutex);
137166
assert(data == buf->bufs[2]);
138167
void *temp_buf = buf->bufs[1];
139168
buf->bufs[1] = buf->bufs[2];
140169
buf->bufs[2] = temp_buf;
141170
set_buffer(dev, temp_buf);
142171
buf->timestamp = timestamp;
143-
buf->valid = 1;
144-
pthread_cond_signal(&buf->cb_cond);
145-
pthread_mutex_unlock(&buf->lock);
172+
buf->valid = true;
173+
buf->cb_cond.notify_one();
146174
}
147175

148176
static void video_producer_cb(freenect_device *dev, void *data, uint32_t timestamp)
@@ -155,71 +183,69 @@ static void depth_producer_cb(freenect_device *dev, void *data, uint32_t timesta
155183
producer_cb_inner(dev, data, timestamp, &((sync_kinect_t *)freenect_get_user(dev))->depth, freenect_set_depth_buffer);
156184
}
157185

158-
/* You should only use these functions to manipulate the pending_runloop_tasks_lock*/
186+
/* You should only use these functions to manipulate the pending_runloop_tasks_mutex*/
159187
static void pending_runloop_tasks_inc(void)
160188
{
161-
pthread_mutex_lock(&pending_runloop_tasks_lock);
189+
LockGuard lock(pending_runloop_tasks_mutex);
162190
assert(pending_runloop_tasks >= 0);
163191
++pending_runloop_tasks;
164-
pthread_mutex_unlock(&pending_runloop_tasks_lock);
165192
}
166193

167194
static void pending_runloop_tasks_dec(void)
168195
{
169-
pthread_mutex_lock(&pending_runloop_tasks_lock);
196+
LockGuard lock(pending_runloop_tasks_mutex);
170197
--pending_runloop_tasks;
171198
assert(pending_runloop_tasks >= 0);
172-
if (!pending_runloop_tasks)
173-
pthread_cond_signal(&pending_runloop_tasks_cond);
174-
pthread_mutex_unlock(&pending_runloop_tasks_lock);
199+
if (!pending_runloop_tasks) {
200+
pending_runloop_tasks_cond.notify_one();
201+
}
175202
}
176203

177204
static void pending_runloop_tasks_wait_zero(void)
178205
{
179-
pthread_mutex_lock(&pending_runloop_tasks_lock);
180-
while (pending_runloop_tasks)
181-
pthread_cond_wait(&pending_runloop_tasks_cond, &pending_runloop_tasks_lock);
182-
pthread_mutex_unlock(&pending_runloop_tasks_lock);
206+
UniqueLock lock(pending_runloop_tasks_mutex);
207+
while (pending_runloop_tasks) {
208+
pending_runloop_tasks_cond.wait(lock);
209+
}
183210
}
184211

185-
static void *init(void *unused)
212+
static void runloop()
186213
{
187214
pending_runloop_tasks_wait_zero();
188-
pthread_mutex_lock(&runloop_lock);
215+
UniqueLock runloop_lock(runloop_mutex);
216+
189217
while (thread_running && freenect_process_events(ctx) >= 0) {
190-
pthread_mutex_unlock(&runloop_lock);
191218
// NOTE: This lets you run tasks while process_events isn't running
219+
runloop_lock.unlock();
192220
pending_runloop_tasks_wait_zero();
193-
pthread_mutex_lock(&runloop_lock);
221+
runloop_lock.lock();
194222
}
195223
// Go through each device, call stop video, close device
196-
int i;
197-
for (i = 0; i < MAX_KINECTS; ++i) {
224+
for (short i = 0; i < MAX_KINECTS; ++i) {
198225
if (kinects[i]) {
199226
freenect_stop_video(kinects[i]->dev);
200227
freenect_stop_depth(kinects[i]->dev);
201-
freenect_set_user(kinects[i]->dev, NULL);
228+
freenect_set_user(kinects[i]->dev, nullptr);
202229
freenect_close_device(kinects[i]->dev);
203230
free_buffer_ring(&kinects[i]->video);
204231
free_buffer_ring(&kinects[i]->depth);
205232
free(kinects[i]);
206-
kinects[i] = NULL;
233+
kinects[i] = nullptr;
207234
}
208235
}
209236
freenect_shutdown(ctx);
210-
pthread_mutex_unlock(&runloop_lock);
211-
return NULL;
212237
}
213238

214239
static void init_thread(void)
215240
{
216-
thread_running = 1;
241+
assert(!thread_running);
242+
thread_running = true;
217243
freenect_init(&ctx, 0);
218244
// We claim both the motor and the camera, because we can't know in advance
219245
// which devices the caller will want, and the c_sync interface doesn't
220246
// support audio, so there's no reason to claim the device needlessly.
221247
freenect_select_subdevices(ctx, (freenect_device_flags)(FREENECT_DEVICE_MOTOR | FREENECT_DEVICE_CAMERA));
222-
pthread_create(&thread, NULL, init, NULL);
248+
thread = Thread(runloop);
223249
}
224250

225251
static int change_video_format(sync_kinect_t *kinect, freenect_resolution res, freenect_video_format fmt)
@@ -248,124 +274,116 @@ static int change_depth_format(sync_kinect_t *kinect, freenect_resolution res, f
248274

249275
static sync_kinect_t *alloc_kinect(int index)
250276
{
251-
sync_kinect_t *kinect = (sync_kinect_t*)malloc(sizeof(sync_kinect_t));
277+
sync_kinect_t* kinect = new sync_kinect_t();
252278
if (freenect_open_device(ctx, &kinect->dev, index)) {
253-
free(kinect);
254-
return NULL;
279+
delete kinect;
280+
return nullptr;
255281
}
256-
int i;
257-
for (i = 0; i < 3; ++i) {
258-
kinect->video.bufs[i] = NULL;
259-
kinect->depth.bufs[i] = NULL;
282+
for (short i = 0; i < 3; ++i) {
283+
kinect->video.bufs[i] = nullptr;
284+
kinect->depth.bufs[i] = nullptr;
260285
}
261286
kinect->video.fmt = -1;
262287
kinect->video.res = -1;
263288
kinect->depth.fmt = -1;
264289
kinect->depth.res = -1;
265290
freenect_set_video_callback(kinect->dev, video_producer_cb);
266291
freenect_set_depth_callback(kinect->dev, depth_producer_cb);
267-
pthread_mutex_init(&kinect->video.lock, NULL);
268-
pthread_mutex_init(&kinect->depth.lock, NULL);
269-
pthread_cond_init(&kinect->video.cb_cond, NULL);
270-
pthread_cond_init(&kinect->depth.cb_cond, NULL);
271292
return kinect;
272293
}
273294

274295
static int setup_kinect(int index, int res, int fmt, int is_depth)
275296
{
276297
pending_runloop_tasks_inc();
277-
pthread_mutex_lock(&runloop_lock);
278-
int thread_running_prev = thread_running;
298+
UniqueLock runloop_lock(runloop_mutex);
299+
300+
bool thread_running_prev = thread_running;
279301
if (!thread_running)
280302
init_thread();
281303
if (!kinects[index]) {
282304
kinects[index] = alloc_kinect(index);
283305
}
284306
if (!kinects[index]) {
285-
printf("Error: Invalid index [%d]\n", index);
307+
FN_WARN_INVALID_INDEX(index);
286308
// If we started the thread, we need to bring it back
287309
if (!thread_running_prev) {
288-
thread_running = 0;
289-
pthread_mutex_unlock(&runloop_lock);
310+
thread_running = false;
311+
runloop_lock.unlock();
290312
pending_runloop_tasks_dec();
291-
pthread_join(thread, NULL);
313+
thread.join();
292314
} else {
293-
pthread_mutex_unlock(&runloop_lock);
315+
runloop_lock.unlock();
294316
pending_runloop_tasks_dec();
295317
}
296318
return -1;
297319
}
298320
freenect_set_user(kinects[index]->dev, kinects[index]);
299-
buffer_ring_t *buf;
300-
if (is_depth)
301-
buf = &kinects[index]->depth;
302-
else
303-
buf = &kinects[index]->video;
304-
pthread_mutex_lock(&buf->lock);
321+
buffer_ring_t *buf = is_depth ? &kinects[index]->depth : &kinects[index]->video;
322+
323+
UniqueLock buffer_lock(buf->mutex);
305324
if ((buf->fmt != fmt) || (buf->res != res))
306325
{
307326
if (is_depth)
308327
change_depth_format(kinects[index], (freenect_resolution)res, (freenect_depth_format)fmt);
309328
else
310329
change_video_format(kinects[index], (freenect_resolution)res, (freenect_video_format)fmt);
311330
}
312-
pthread_mutex_unlock(&buf->lock);
313-
pthread_mutex_unlock(&runloop_lock);
331+
buffer_lock.unlock();
314332
pending_runloop_tasks_dec();
315333
return 0;
316334
}
317335

318336
static int sync_get(void **data, uint32_t *timestamp, buffer_ring_t *buf)
319337
{
320-
pthread_mutex_lock(&buf->lock);
338+
UniqueLock buffer_lock(buf->mutex);
321339
// If there isn't a frame ready for us
322-
while (!buf->valid)
323-
pthread_cond_wait(&buf->cb_cond, &buf->lock);
340+
while (!buf->valid) {
341+
buf->cb_cond.wait(buffer_lock);
342+
}
324343
void *temp_buf = buf->bufs[0];
325344
*data = buf->bufs[0] = buf->bufs[1];
326345
buf->bufs[1] = temp_buf;
327-
buf->valid = 0;
346+
buf->valid = false;
328347
*timestamp = buf->timestamp;
329-
pthread_mutex_unlock(&buf->lock);
330348
return 0;
331349
}
332350

333351

334-
/*
352+
/*
335353
Use this to make sure the runloop is locked and no one is in it. Then you can
336354
call arbitrary functions from libfreenect.h in a safe way. If the kinect with
337-
this index has not been initialized yet, then it will try to set it up. If
355+
this index has not been initialized yet, then it will try to set it up. If
338356
this function is successful, then you can access kinects[index]. Don't forget
339357
to unlock the runloop when you're done.
340-
358+
341359
Returns 0 if successful, nonzero if kinect[index] is unvailable
342-
*/
360+
*/
343361
static int runloop_enter(int index)
344362
{
345363
if (index < 0 || index >= MAX_KINECTS) {
346-
printf("Error: Invalid index [%d]\n", index);
364+
FN_WARN_INVALID_INDEX(index);
347365
return -1;
348366
}
349367
if (!thread_running || !kinects[index])
350368
if (setup_kinect(index, FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_11BIT, 1))
351369
return -1;
352-
370+
353371
pending_runloop_tasks_inc();
354-
pthread_mutex_lock(&runloop_lock);
372+
runloop_mutex.lock();
355373
return 0;
356374
}
357375

358376
static void runloop_exit()
359377
{
360-
pthread_mutex_unlock(&runloop_lock);
378+
runloop_mutex.unlock();
361379
pending_runloop_tasks_dec();
362380
}
363381

364382
int freenect_sync_get_video_with_res(void **video, uint32_t *timestamp, int index,
365383
freenect_resolution res, freenect_video_format fmt)
366384
{
367385
if (index < 0 || index >= MAX_KINECTS) {
368-
printf("Error: Invalid index [%d]\n", index);
386+
FN_WARN_INVALID_INDEX(index);
369387
return -1;
370388
}
371389
if (!thread_running || !kinects[index] || kinects[index]->video.fmt != fmt || kinects[index]->video.res != res)
@@ -384,7 +402,7 @@ int freenect_sync_get_depth_with_res(void **depth, uint32_t *timestamp, int inde
384402
freenect_resolution res, freenect_depth_format fmt)
385403
{
386404
if (index < 0 || index >= MAX_KINECTS) {
387-
printf("Error: Invalid index [%d]\n", index);
405+
FN_WARN_INVALID_INDEX(index);
388406
return -1;
389407
}
390408
if (!thread_running || !kinects[index] || kinects[index]->depth.fmt != fmt
@@ -404,7 +422,7 @@ int freenect_sync_get_tilt_state(freenect_raw_tilt_state **state, int index)
404422
{
405423
if (runloop_enter(index)) return -1;
406424
freenect_update_tilt_state(kinects[index]->dev);
407-
*state = freenect_get_tilt_state(kinects[index]->dev);
425+
*state = freenect_get_tilt_state(kinects[index]->dev);
408426
runloop_exit();
409427
return 0;
410428
}
@@ -433,7 +451,7 @@ int freenect_sync_camera_to_world(int cx, int cy, int wz, double* wx, double* wy
433451
void freenect_sync_stop(void)
434452
{
435453
if (thread_running) {
436-
thread_running = 0;
437-
pthread_join(thread, NULL);
454+
thread_running = false;
455+
thread.join();
438456
}
439457
}

0 commit comments

Comments
 (0)
Please sign in to comment.