2011-12-09 36 views
6

TRẢ LỜITại sao PyGILState_Release ném lỗi Python Fatal

Ok, tôi giải quyết vấn đề này. Tất cả trong cách bạn khởi tạo trạng thái luồng. Bạn không cần sử dụng ReleaseLock chút nào. Chỉ cần thêm InitThreads gọi để định nghĩa module của bạn:

BOOST_PYTHON_MODULE(ModuleName) 
{ 
    PyEval_InitThreads(); 

    ... 
} 

Ok, tôi đã cố gắng để chẩn đoán vấn đề này trong nhiều giờ và đổ qua những gì có vẻ như mỗi ví dụ trên web. Bây giờ tôi cảm thấy mệt mỏi vì vậy tôi có thể thiếu điều gì đó hiển nhiên nhưng đây là những gì đang xảy ra:

Tôi đang gói một thư viện bằng python tăng cường. Tôi đang chạy một kịch bản python mà nhập khẩu lib, xây dựng một số đối tượng và sau đó nhận được callbacks từ c + + mà các cuộc gọi trở lại vào python. Trước khi tôi gọi bất kỳ hàm python nào, tôi cố gắng lấy khóa thông dịch toàn cầu. Dưới đây là một số mã mẫu:

class ScopedGILRelease 
{ 
public: 
    inline ScopedGILRelease() 
    { 
     d_gstate = PyGILState_Ensure(); 
    } 

    inline ~ScopedGILRelease() 
    { 
     PyGILState_Release(d_gstate); 
    } 

private: 
    PyGILState_STATE d_gstate; 
}; 

class PyTarget : public DingoClient::ClientRequest::Target, public wrapper<DingoClient::ClientRequest::Target> 
{ 
    public: 
    PyTarget(PyObject* self_) : self(self_) {} 
    ~PyTarget() { 
     ScopedGILRelease gil_lock; 
    } 
    PyObject* self; 

    void onData(const boost::shared_ptr<Datum>::P & data, const void * closure) 
    { 
     ScopedGILRelease gil_lock; 
     // invoke call_method to python 
    } 

    ... 
} 

Phương pháp onData trên đối tượng đích được gọi bởi thư viện dưới dạng gọi lại. Trong python, chúng ta kế thừa từ PyTarget và thực hiện một phương thức khác. Sau đó, chúng tôi sử dụng call_method <> để gọi phương thức đó. gil_lock mua lại khóa và thông qua RIAA đảm bảo rằng trạng thái luồng thu được luôn là bản phát hành duy nhất và thực tế nó luôn luôn được giải phóng khi đi ra ngoài phạm vi.

Tuy nhiên khi tôi chạy điều này trong tập lệnh cố gắng thu được số lượng lớn các cuộc gọi lại trên chức năng này, nó luôn luôn segfaults. Script trông giống như sau:

# Initialize the library and setup callbacks 
... 

# Wait until user breaks 
while 1: 
    pass 

Ngoài ra, các kịch bản python luôn xây dựng một đối tượng mà chạy:

PyEval_InitThreads(); 
PyEval_ReleaseLock(); 

trước khi nhận bất kỳ callbacks.

Tôi đã giảm mã xuống nơi tôi thậm chí không gọi vào python trong onData, tôi vừa mua khóa. Khi được thả nó luôn tai nạn với một trong hai:

Fatal Python error: ceval: tstate mix-up 
Fatal Python error: This thread state must be current when releasing 

hoặc

Fatal Python error: ceval: orphan tstate 
Fatal Python error: This thread state must be current when releasing 

Đó là dường như ngẫu nhiên. Tôi có điên ở đây không, bởi vì tôi cảm thấy như tôi đang sử dụng khóa GIL một cách chính xác, tuy nhiên nó dường như không hoạt động chút nào.

Ghi chú khác: Chỉ một chủ đề bao giờ gọi phương thức onData của đối tượng mục tiêu.

Khi tôi ngủ trong vòng lặp while trong mô-đun python gọi với time.sleep(), có vẻ như cho phép tập lệnh chạy lâu hơn nhưng cuối cùng tập lệnh sẽ phân biệt với các vấn đề tương tự. Khoảng thời gian nó kéo dài tỷ lệ thuận với lượng thời gian ngủ (tức là time.sleep (10) chạy lâu hơn time.sleep (0,01). Điều này làm cho tôi nghĩ một số kịch bản đang lấy lại GIL mà không được tôi cho phép

PyGILState_Release và PyGILState_Ensure được gọi là không có nơi nào khác trong mã của tôi, không có nơi nào khác nên được gọi vào python.

Cập nhật

Tôi đã đọc một câu hỏi mà cho thấy luồng nhập khẩu trong các mô-đun như một thay thế cho chạy

PyEval_InitThreads(); 
PyEval_ReleaseLock(); 

Tuy nhiên, nó không xuất hiện để làm việc khi tôi nhập khẩu luồng trước của tôi mô-đun và loại bỏ hai dòng trên từ trình bao bọc python tăng cường của tôi.

+1

Rất vui khi bạn tìm ra. Đó là một trong những đã cho tôi quá, trở lại khi nào. FYI, bạn có thể đăng câu trả lời cho câu hỏi của riêng bạn. Điều đó sẽ cho phép những người thích giải pháp của bạn để bỏ phiếu. –

+0

Cảm ơn, tương đối mới để ngăn xếp tràn và vẫn nhận được hang của nó. Sẽ đăng. –

Trả lời

5

Ok, tôi đã giải quyết vấn đề này. Tất cả trong cách bạn khởi tạo trạng thái luồng. Bạn không cần sử dụng ReleaseLock chút nào. Chỉ cần thêm InitThreads gọi vào định nghĩa mô-đun của bạn:

BOOST_PYTHON_MODULE(ModuleName) 
{ 
    PyEval_InitThreads(); 

    ... 
} 
+0

cảm ơn anh chàng. đã giúp tôi. – genjix

Các vấn đề liên quan