2012-12-28 38 views
6

Tôi đang chơi xung quanh với một số ổ cắm, ren và mutex. Câu hỏi của tôi liên quan đến chủ đề và mutexes:Mở khóa Mutex không thành công lạ

int ConnectionHandler::addNewSocket(){ 

    this->connectionList_mutex.lock(); 
    std::cout << "test1" << std::endl; 
    this->connectionList_mutex.unlock(); 

    return 0; 
} 

int ConnectionHandler::main(){ 
    while(true){ 
     this->connectionList_mutex.lock(); 
     std::cout << "test2" << std::endl; 
     this->connectionList_mutex.unlock(); 
    } 

}` 

Chức năng chính đang chạy trong một chuỗi, trong khi addNewSocket được gọi bởi một chuỗi khác. Vấn đề là, khi addNewSocket được gọi một lần (theo luồng thứ hai), mở khóa tiếp theo theo luồng 1 (chính) sẽ thất bại với một tín hiệu lạ "SIGABRT". Tôi đã làm việc hai ngày về điều này bây giờ, nhưng tôi đã không quản lý để làm cho nó cố định, thật đáng buồn. Tôi hy vọng bạn có thể giúp tôi.

Chỉnh sửa: ConnectionHandler là một lớp, có connectionList_mutex là thành viên.

Chỉnh sửa: Đôi khi tôi cũng gặp phải lỗi này: "Xác nhận không thành công: (ec == 0), mở khóa chức năng, tệp /SourceCache/libcxx/libcxx-65.1/src/mutex.cpp, dòng 44." nhưng nó xảy ra ngẫu nhiên.

Chỉnh sửa: Đây là toàn bộ lớp (Giảm đến mức tối thiểu, phải là bối cảnh độc lập ở mức độ nhất định, nhưng bị treo khi tôi đặt nó ngay sau khi khách hàng kết nối và hoạt động nếu tôi đặt ngay sau khi bắt đầu:

..
class ConnectionHandler{ 
public: 
    ConnectionHandler(); 
    int addNewSocket(); 
private: 
    int main(); 
    static void start(void * pThis); 

    std::mutex connectionList_mutex; 
}; 

ConnectionHandler::ConnectionHandler(){ 
    std::thread t(&this->start, this); 
    t.detach(); 
} 
void ConnectionHandler::start(void * pThis){ 
    ConnectionHandler *handlerThis; 
    handlerThis = (ConnectionHandler *)pThis; 
    handlerThis->main(); 
} 


int ConnectionHandler::addNewSocket(){ 

    this->connectionList_mutex.lock(); 
    std::cout << "test1" << std::endl; 
    this->connectionList_mutex.unlock(); 

    return 0; 
} 

int ConnectionHandler::main(){ 
    while(true){ 
     this->connectionList_mutex.lock(); 
     std::cout << "test2" << std::endl; 
     std::this_thread::sleep_for(std::chrono::milliseconds(100)); 
     this->connectionList_mutex.unlock(); 

    } 

} 
+0

Tại sao thẻ std? Là mutex std của bạn :: mutex hoặc một cái gì đó? –

+0

có mutex và thread đều là C++ 11 std – sh4kesbeer

+0

ok, có lẽ tôi ngu ngốc, nhưng bây giờ (tôi đã tạo ra một mã nhỏ) hoạt động, tôi chỉ cần tìm ra, tại sao nó không hoạt động trong ngữ cảnh của tôi chương trình thực sự – sh4kesbeer

Trả lời

5

tôi đoán là đối tượng ConnectionHandler của bạn đang bị hủy hoại ở đâu đó Ngoài ra, bạn đã xác định ConnectionHandler::start một cách ngớ ngẩn

Thứ nhất, ConnectionHandler::start cần được xác định theo cách này:

void ConnectionHandler::start(ConnectionHandler * pThis){ 
    pThis->main(); 
} 

Lớp C++ 11 ::std::thread hoàn toàn có khả năng bảo toàn loại đối số hàm do đó không cần phải sử dụng đến void *.

Thứ hai, thêm vào mã này:

void ConnectionHandler::~ConnectionHandler(){ 
    const void * const meptr = this; 
    this->connectionList_mutex.lock(); 
    ::std::cout << "ConnectionHandler being destroyed at " << meptr << ::std::endl; 
    this->connectionList_mutex.unlock(); 
} 

Và thay đổi các nhà xây dựng để đọc:

ConnectionHandler::ConnectionHandler(){ 
    const void * const meptr = this; 
    ::std::cout << "ConnectionHandler being created at " << meptr << ::std::endl; 
    std::thread t(&this->start, this); 
    t.detach(); 
} 

này sẽ cho bạn thấy khi đối tượng ConnectionHandler đang bị hủy hoại. Và tôi đoán là mã của bạn đang phá hủy nó trong khi chuỗi tách rời của bạn vẫn đang chạy.

Điều meptr là vì operator << có quá tải cho void * để in giá trị con trỏ. In ra giá trị con trỏ cho this sẽ cho phép bạn kết hợp các cuộc gọi với hàm tạo và hàm hủy nếu bạn đang tạo nhiều đối tượng ConnectionHandler.

Edit: Kể từ khi nó bật ra tôi là đúng, đây là cách tôi muốn giới thiệu bạn viết lớp chơi ConnectionHandler:

#include <iostream> 
#include <atomic> 
#include <thread> 
#include <chrono> 
#include <mutex> 

class ConnectionHandler { 
public: 
    ConnectionHandler(); 
    ~ConnectionHandler(); 
    ConnectionHandler(const ConnectionHandler &) = delete; 
    const ConnectionHandler &operator =(const ConnectionHandler &) = delete; 

    int addNewSocket(); 

private: 
    int main(); 
    static void start(ConnectionHandler * pThis); 

    ::std::mutex connectionList_mutex; 
    volatile ::std::atomic_bool thread_shutdown; 
    ::std::thread thread; 
}; 

ConnectionHandler::ConnectionHandler() 
    : thread_shutdown(false), thread(&this->start, this) 
{ 
} 

ConnectionHandler::~ConnectionHandler() 
{ 
    thread_shutdown.store(true); 
    thread.join(); 
} 

void ConnectionHandler::start(ConnectionHandler * pThis){ 
    pThis->main(); 
} 

int ConnectionHandler::addNewSocket(){ 
    ::std::lock_guard< ::std::mutex> lock(connectionList_mutex); 
    ::std::cout << "test1" << ::std::endl; 

    return 0; 
} 

int ConnectionHandler::main(){ 
    while(!thread_shutdown.load()){ 
     ::std::lock_guard< ::std::mutex> lock(connectionList_mutex); 
     ::std::cout << "test2" << ::std::endl; 
     ::std::this_thread::sleep_for(::std::chrono::milliseconds(100)); 

    } 
    return 0; 
} 
+1

Đầu tiên: Cảm ơn rất nhiều, các bạn ở đây tại stackoverflow thật tuyệt vời! Hy vọng rằng một ngày nào đó tôi sẽ có đủ kỹ năng để giúp mọi người, giống như bạn. Thứ hai: Bây giờ tôi biết rằng ConnectionHandler bị phá hủy ngay sau khi nó được tạo ra, tôi bắt đầu điều tra điều này, mà không có gợi ý tốt của bạn, tôi có lẽ đã từ bỏ dự án này, bởi vì tôi đã cố sửa lỗi trong một tuần :) – sh4kesbeer

+0

Ok, tôi đã tìm thấy lỗi: Tôi đã tạo ConnectionHandler trong một hàm và ngay sau khi hàm kết thúc, cá thể đã bị hủy. Trong kết nối với [link] này (http://stackoverflow.com/questions/6403055/object-destruction-in-c) tôi đã tìm ra, rằng tôi phải tạo một con trỏ trỏ đến một trình xử lý được tạo bằng "mới "toán tử (ConnectionHandler * newHandler = new ConnectionHandler;). Trong trường hợp này (như tôi không hiểu) con trỏ bị phá hủy, nhưng thể hiện của ConnectionHandler vẫn nằm trong bộ nhớ. Một lần nữa: Cảm ơn sự giúp đỡ của các bạn! – sh4kesbeer

+0

@ sh4kesbeer: Đó vẫn là giải pháp sai. Bạn cần phải suy nghĩ về chủ đề 'sở hữu' đối tượng ConnectionManager. Trong trường hợp này, sự lựa chọn thực sự duy nhất là sợi tách ra vì chuỗi đó cần đối tượng miễn là nó tồn tại và bạn không có cách nào để tắt nó đi. Điều này có nghĩa là bạn cần phải có một cách để 'hỏi' sợi tách rời để phá hủy đối tượng của bạn và tự tắt nó. Tạo ra nó với các loại tác phẩm 'mới', nhưng nó tạo ra một rò rỉ bộ nhớ và là một giải pháp tổng thể lộn xộn. – Omnifarious

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