2012-10-28 4 views
0

Python C API에 매우 이상한 문제가 있습니다. PyObject '장치'멤버가 포함 된 전역 적으로 범위가 지정된 구조체 'dcon'이 있습니다.PyObject_HasAttrString 속성이 존재하지 않을 때 segfaults, 존재하지 않는 경우

static status_t get_mac_addr(uint8_t const ** addr, 
          size_t * const size){ 
    static uint8_t device_mac_addr[6] = {0}; 
    *addr = device_mac_addr; 
    *size = sizeof device_mac_addr; 

    if(PyObject_HasAttrString(dcon.device, "mac_address") == 1){ 
     ...   
    } 
    return 0; 
} 

'mac_address'속성이있을 때마다 코드가 올바르게 실행됩니다. 이상하게도, 'mac_address'가 정의 된 속성이 아닌 경우 segault (Segmentation fault (core dumped))가 발생합니다.

(gdb) bt 
#0 0x00000000004ca607 in PyErr_Restore() 
#1 0x00000000004aa29f in PyErr_Format() 
#2 0x000000000049e6ee in _PyObject_GenericGetAttrWithDict() 
#3 0x0000000000486387 in PyObject_GetAttrString() 
#4 0x00000000004ea7d7 in PyObject_HasAttrString() 
#5 0x00007ffff4f2056d in get_mac_addr (size=0x7ffff4f1cd28, addr=<optimized out>) at config.c:165 

내가 파이썬 C API를 사용하여 초보자의 비트 해요 다음은 세그멘트 폴트가 발생 역 추적입니다. 내 초기 생각은 내가 참조 카운팅에 문제가있어,하지만 난 그 주위에 내 머리를 포장하는 것 수 없습니다.

+1

더 많은 코드없이 말하기가 어렵습니다. 출시 된 GIL이 한 가지 이유 일 수 있습니다. 그렇다면 파이썬 API를 사용하는 코드 주위에서 PyGILState_Ensure()와 PyGILState_Release()를 호출해야 할 것이다. – yak

+0

@yak Ahh, 나는 그것이 나에게 일어나지 않았다는 것을 믿을 수 없다. 나는 2 개의 쓰레드를 가지고 있고 그것에 대해 생각할 것이므로 이것은 문제를 일으킬 것입니다. 방금 추가해야했습니다 : 'PyGILState_STATE gstate; gstate = PyGILState_Ensure();' PyObject_HasAttrString()을 호출하기 전에 해당 변수를 공개하십시오. 도와 주셔서 감사합니다. 답변을 추가하면 해결할 수 있습니다. :) – weak

+0

기꺼이 도와 드리겠습니다. 나는 대답을 추가했다. – yak

답변

1

멀티 스레드 응용 프로그램에서 파이썬 C API 함수를 호출하는 스레드는 먼저 스레드가 전역 인터프리터 잠금을 보유하고 있는지 확인해야합니다. 파이썬 코드에서 호출 된 함수의 경우 잠금이 이미 유지되어 있기 때문에 문제가되지 않습니다.

이것은 인터프리터 외부에서 호출 된 코드 (콜백 등)에는 해당되지 않습니다.

파이썬 API 함수가 안전하게 호출되기 전에 GIL을 획득해야합니다.

PyGILState_STATE gstate; 
gstate = PyGILState_Ensure(); 

... 

PyGILState_Release(gstate); 

이뿐만 아니라 GIL 개최되는 것을 보장뿐만 아니라 (직접 OS 호출하지 thread.start_new_thread()를 사용하여) 파이썬의 외부에서 생성 된 스레드 파이썬 스레드 상태를 만듭니다.

파이썬 API를 호출하는 동안 발생할 수있는 모든 파이썬 예외는 GIL을 해제하기 전에 처리해야합니다.

다른 스레드가 현재 잠금을 보유하고있는 경우 (예 : Python 코드를 실행하고 있기 때문에) 잠금 확인이 다른 스레드에서 잠금을 해제 할 때까지 차단됩니다.

Ensure() 호출이 모두 Release()와 일치하는 경우 잠금을 이미 획득 한 경우에도 이러한 호출을 사용하는 것이 좋습니다.

+0

추가 설명 주셔서 감사합니다! GetAttr이 오류를 발생 시키므로 이제는 더 나에게 이해가됩니다. 따라서 GIL을 얻어야합니다. 나머지 코드에서는 적절한 조정을했습니다. – weak

관련 문제