Skip to content

Commit 0afe0b2

Browse files
committed
Fixed memory leak
1 parent ce1514a commit 0afe0b2

File tree

4 files changed

+57
-22
lines changed

4 files changed

+57
-22
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ $ scandocument -c 1 -l <license-key>
290290
normalized_image.save(<filename>)
291291
```
292292
- `normalized_image.recycle()` # release the memory of the normalized image
293-
293+
- `clearAsyncListener()` # stop the native thread and clear the registered Python function
294294
## C/C++ API
295295
To customize Python API based on C/C++, please refer to the
296296
[online documentation](https://www.dynamsoft.com/document-normalizer/docs/programming/c/api-reference/?ver=latest).

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def run(self):
8383

8484

8585
setup(name='document-scanner-sdk',
86-
version='1.0.1',
86+
version='1.0.2',
8787
description='Document Scanner SDK for document edge detection, border cropping, perspective correction and brightness adjustment',
8888
long_description=long_description,
8989
long_description_content_type="text/markdown",

src/docscanner.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ static PyObject *createInstance(PyObject *obj, PyObject *args)
4646
reader->callback = NULL;
4747
return (PyObject *)reader;
4848
}
49-
49+
5050
static PyObject *initLicense(PyObject *obj, PyObject *args)
5151
{
5252
char *pszLicense;
@@ -101,3 +101,4 @@ PyMODINIT_FUNC PyInit_docscanner(void)
101101
PyModule_AddStringConstant(module, "version", DDN_GetVersion());
102102
return module;
103103
}
104+

src/document_scanner.h

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,19 @@
1212
#include <queue>
1313
#include <functional>
1414

15+
class Task
16+
{
17+
public:
18+
std::function<void()> func;
19+
unsigned char* buffer;
20+
};
21+
1522
class WorkerThread
1623
{
1724
public:
1825
std::mutex m;
1926
std::condition_variable cv;
20-
std::queue<std::function<void()>> tasks = {};
27+
std::queue<Task> tasks = {};
2128
volatile bool running;
2229
std::thread t;
2330
};
@@ -30,30 +37,47 @@ typedef struct
3037
WorkerThread *worker;
3138
} DynamsoftDocumentScanner;
3239

33-
static int DynamsoftDocumentScanner_clear(DynamsoftDocumentScanner *self)
40+
void clearTasks(DynamsoftDocumentScanner *self)
3441
{
35-
if (self->callback)
42+
if (self->worker->tasks.size() > 0)
3643
{
37-
Py_XDECREF(self->callback);
38-
self->callback = NULL;
44+
for (int i = 0; i < self->worker->tasks.size(); i++)
45+
{
46+
free(self->worker->tasks.front().buffer);
47+
self->worker->tasks.pop();
48+
}
3949
}
50+
}
4051

41-
if (self->handler)
52+
void clear(DynamsoftDocumentScanner *self)
53+
{
54+
if (self->callback)
4255
{
43-
DDN_DestroyInstance(self->handler);
44-
self->handler = NULL;
56+
Py_XDECREF(self->callback);
57+
self->callback = NULL;
4558
}
4659

4760
if (self->worker)
4861
{
4962
self->worker->running = false;
63+
clearTasks(self);
5064
self->worker->cv.notify_one();
5165
self->worker->t.join();
5266
delete self->worker;
5367
self->worker = NULL;
54-
// printf("Quit native thread.\n");
68+
printf("Quit native thread.\n");
5569
}
70+
}
5671

72+
static int DynamsoftDocumentScanner_clear(DynamsoftDocumentScanner *self)
73+
{
74+
clear(self);
75+
76+
if (self->handler)
77+
{
78+
DDN_DestroyInstance(self->handler);
79+
self->handler = NULL;
80+
}
5781
return 0;
5882
}
5983

@@ -253,7 +277,7 @@ void scan(DynamsoftDocumentScanner *self, unsigned char *buffer, int width, int
253277
int ret = DDN_DetectQuadFromBuffer(self->handler, &data, "", &pResults);
254278
if (ret)
255279
{
256-
// printf("Detection error: %s\n", DC_GetErrorString(ret));
280+
printf("Detection error: %s\n", DC_GetErrorString(ret));
257281
}
258282

259283
free(buffer);
@@ -278,15 +302,15 @@ static PyObject *detectMatAsync(PyObject *obj, PyObject *args)
278302
DynamsoftDocumentScanner *self = (DynamsoftDocumentScanner *)obj;
279303
PyObject *o;
280304
if (!PyArg_ParseTuple(args, "O", &o))
281-
return NULL;
305+
return Py_BuildValue("i", -1);
282306

283307
Py_buffer *view;
284308
int nd;
285309
PyObject *memoryview = PyMemoryView_FromObject(o);
286310
if (memoryview == NULL)
287311
{
288312
PyErr_Clear();
289-
return NULL;
313+
return Py_BuildValue("i", -1);
290314
}
291315

292316
view = PyMemoryView_GET_BUFFER(memoryview);
@@ -316,13 +340,12 @@ static PyObject *detectMatAsync(PyObject *obj, PyObject *args)
316340
memcpy(data, buffer, len);
317341

318342
std::unique_lock<std::mutex> lk(self->worker->m);
319-
if (self->worker->tasks.size() > 1)
320-
{
321-
std::queue<std::function<void()>> empty = {};
322-
std::swap(self->worker->tasks, empty);
323-
}
343+
clearTasks(self);
324344
std::function<void()> task_function = std::bind(scan, self, data, width, height, stride, format, len);
325-
self->worker->tasks.push(task_function);
345+
Task task;
346+
task.func = task_function;
347+
task.buffer = data;
348+
self->worker->tasks.push(task);
326349
self->worker->cv.notify_one();
327350
lk.unlock();
328351

@@ -342,7 +365,7 @@ void run(DynamsoftDocumentScanner *self)
342365
{
343366
break;
344367
}
345-
task = std::move(self->worker->tasks.front());
368+
task = std::move(self->worker->tasks.front().func);
346369
self->worker->tasks.pop();
347370
lk.unlock();
348371

@@ -385,6 +408,16 @@ static PyObject *addAsyncListener(PyObject *obj, PyObject *args)
385408
return Py_BuildValue("i", 0);
386409
}
387410

411+
/**
412+
* Clear native thread and tasks.
413+
*/
414+
static PyObject *clearAsyncListener(PyObject *obj, PyObject *args)
415+
{
416+
DynamsoftDocumentScanner *self = (DynamsoftDocumentScanner *)obj;
417+
clear(self);
418+
return Py_BuildValue("i", 0);
419+
}
420+
388421
static PyObject *setParameters(PyObject *obj, PyObject *args)
389422
{
390423
DynamsoftDocumentScanner *self = (DynamsoftDocumentScanner *)obj;
@@ -543,6 +576,7 @@ static PyMethodDef instance_methods[] = {
543576
{"setParameters", setParameters, METH_VARARGS, NULL},
544577
{"normalizeFile", normalizeFile, METH_VARARGS, NULL},
545578
{"normalizeBuffer", normalizeBuffer, METH_VARARGS, NULL},
579+
{"clearAsyncListener", clearAsyncListener, METH_VARARGS, NULL},
546580
{NULL, NULL, 0, NULL}
547581
};
548582

0 commit comments

Comments
 (0)