2012-10-28 49 views
0

我遇到了Python C API的一個非常奇怪的問題。我有一個全局範圍的結構'dcon',它包含一個PyObject的'設備'成員。PyObject_HasAttrString段錯誤當屬性不存在時,不存在時

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))。下面是遇到段錯誤時,回溯:我有點使用Python C API是新手的

(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 

。我最初的想法是,我在引用計數方面做了一些錯誤的工作,但似乎無法繞過它。

+1

很難說沒有更多的代碼。發佈GIL可能是其中一個原因。如果是這種情況,您需要在使用Python API的代碼周圍調用PyGILState_Ensure()和PyGILState_Release()。 – yak

+0

@yak啊,我簡直不敢相信這一切都不會發生在我身上。我有2個線程,現在我想到了,這不會引起問題。我只需要添加: 'PyGILState_STATE gstate;在我調用PyObject_HasAttrString()之前釋放它之前,gstate = PyGILState_Ensure(); 。感謝您的幫助,如果您添加答案,我會將其標記爲已解決:) – weak

+0

很高興我能提供幫助。我添加了一個答案。 – yak

回答

1

在多線程應用程序中,任何調用Python C API函數的線程都必須首先確保線程持有全局解釋器鎖。對於從Python代碼調用的函數來說,這不是問題,因爲鎖已經被佔用了。

這不是從解釋器外部調用的代碼(回調等)。

在這種情況下,必須先獲取GIL,然後才能安全地調用Python API函數。

PyGILState_STATE gstate; 
gstate = PyGILState_Ensure(); 

... 

PyGILState_Release(gstate); 

這不僅保證了GIL舉行,但它也已經Python的以外創建的線程(使用直接的OS調用,而不是thread.start_new_thread())創建了Python線程狀態。

調用Python API時可能發生的任何Python異常必須在釋放GIL之前處理。

請注意,如果另一個線程當前持有鎖(例如因爲它正在執行Python代碼),則Ensure調用將阻塞,直到其他線程釋放鎖。

即使已經獲取了鎖,也可以使用這些調用,前提是每次調用Ensure()都有與Release()的匹配調用。

+0

感謝您的進一步解釋!這現在對我來說更有意義,因爲GetAttr會引發錯誤,因此必須獲取GIL。我在我的其他代碼中做出了相應的調整。 – weak

相關問題