【问题标题】:Segmentation fault when using ctypes and threading使用 ctypes 和线程时出现分段错误
【发布时间】:2016-10-23 12:16:28
【问题描述】:

我使用ctypes 为 C 库编写了 Python 包装器。一切正常,直到我尝试使用 threading 模块。

这是一个重现它的小例子:

foo.c

#include <stdlib.h>
#include <assert.h>

char *foo_init() {
    char *result = (char*)malloc(sizeof(char));
    assert(result);
    return result;
}

char foo_get(const char* p) {
    return *p;
}

void foo_set(char *p, char value) {
    *p = value;
}

void foo_del(char *p) {
    free(p);
}

foo.py

import threading
import ctypes
libfoo=ctypes.CDLL('foo.so')

libfoo.foo_init.restype = ctypes.c_void_p
libfoo.foo_get.restype = ctypes.c_char

class Foo:
    def __init__(self):
        self.__obj__ = libfoo.foo_init()

    def get(self):
        return libfoo.foo_get(self.__obj__)

    def set(self, value):
        libfoo.foo_set(self.__obj__, ctypes.c_char(value))

    def __del__(self):
        libfoo.foo_del(self.__obj__)

x = Foo()
x.set(b'x')
print(x.get())

def compute():
    y = Foo()
    y.set(b'y')
    print(y.get())

t = threading.Thread(target=compute)
t.start()
t.join()

编译:

gcc -Wall -shared -o foo.so -fPIC foo.c

执行:

export LD_LIBRARY_PATH=.
python3 foo.py

结果:

b'x'
[1]    8627 segmentation fault  python3 foo.py

我们在这里看到x.get() 打印正确,而y.get() 出现分段错误。因此,似乎存在与ctypesthreading 相关的问题。

请注意,如果我将y 的初始化移到compute 函数之外,则程序会正常退出。

此外,每个操纵指针的函数都会产生分段错误(例如,如果我只保留 __init____del__ 函数,仍然会发生崩溃)。

知道如何解决这个问题吗?

【问题讨论】:

  • 您设置了错误的返回类型,并且您没有设置任何参数类型。修复这些问题,看看结果是否有所不同。
  • 我应该使用什么返回类型?我尝试了 c_char_p,但随后出现错误 *** `python3' 中的错误:munmap_chunk(): invalid pointer: 0x00007fd25ec0da28 *** 根据文档,c_char_p 用于 NUL 终止的 char*,这里不是这种情况。
  • 引用docs,“对于也可能指向二进制数据的通用字符指针,必须使用POINTER(c_char)。”。
  • 非常感谢,它解决了我的问题。我发布了一个带有代码修改的答案。

标签: python c multithreading segmentation-fault ctypes


【解决方案1】:

@user2357112 在 cmets 中给了我答案:添加(好的)返回类型和参数类型很重要。

foo.py 的开头替换为以下解决问题:

libfoo.foo_init.restype = ctypes.POINTER(ctypes.c_char)
libfoo.foo_init.argtypes = []
libfoo.foo_get.restype = ctypes.c_char
libfoo.foo_get.argtypes = [ctypes.POINTER(ctypes.c_char)]
libfoo.foo_set.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.c_char]
libfoo.foo_del.argtypes = [ctypes.POINTER(ctypes.c_char)]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多