2010-02-25 52 views
6

Tôi đang tìm kiếm một lock-free thiết kế phù hợp với những điều kiện tiên quyết:Looking for a RT-an toàn cấu trúc đơn-reader đơn nhà văn lock-free

  • một nhà văn đơn viết thành một cấu trúc và một đọc đơn đọc từ cấu trúc này (cấu trúc này đã tồn tại và an toàn cho đồng thời đọc/ghi)
  • nhưng tại một thời gian, cấu trúc cần phải được thay đổi bởi nhà văn, sau đó initialises, công tắc và viết vào một cấu trúc mới (cùng loại nhưng có nội dung mới)
  • và vào lần tiếp theo người đọc đọc, nó thiết bị chuyển mạch đến cấu trúc mới này (nếu nhà văn nhân chuyển sang cấu trúc không có khóa mới) các cấu trúc này, bỏ qua dữ liệu của chúng).
  • Cấu trúc phải được sử dụng lại, nghĩa là không được cấp phát bộ nhớ heap/miễn phí trong khi hoạt động ghi/đọc/chuyển đổi, cho mục đích RT.

Tôi hiện đã triển khai trình tạo vòng đeo có chứa nhiều phiên bản của các cấu trúc này; nhưng việc triển khai này thực tế là khi người viết đã sử dụng tất cả các cấu trúc có trong ringbuffer, không còn chỗ nào để thay đổi từ cấu trúc ... Nhưng phần còn lại của ringbuffer chứa một số dữ liệu mà không cần phải đọc bởi người đọc nhưng không thể được sử dụng lại bởi nhà văn. Kết quả là, các ringbuffer không phù hợp với mục đích này.

Bất kỳ ý tưởng (tên hoặc giả thực hiện) thiết kế không có khóa? Cảm ơn bạn đã xem xét vấn đề này.

+3

Sự nhấn mạnh quá nhiều không làm nhấn mạnh. – kennytm

+0

@KennyTM: Bạn nói đúng. Đã chỉnh sửa. – moala

+1

Câu hỏi hay. Đây là một vấn đề thường gặp trong các hệ thống thời gian thực. Tôi rất tò mò nếu có cách nào để thực hiện điều này. – thebretness

Trả lời

0

Bạn đang đi đúng hướng.

Khóa giao tiếp miễn phí các thông điệp cố định giữa các chủ đề/quá trình/xử lý alt text http://img59.imageshack.us/img59/5273/basicq.gif

kích thước cố định bộ đệm vòng có thể được sử dụng trong thông tin liên lạc miễn phí khóa giữa các chủ đề, quy trình hoặc xử lý nếu có một nhà sản xuất và một khách hàng. Một số kiểm tra để thực hiện:

đầu biến được viết chỉ bằng cách sản xuất (như là một hành động nguyên tử sau khi văn bản)

đuôi biến được viết chỉ bởi người tiêu dùng (như là một hành động nguyên tử sau khi đọc)

Pitfall: giới thiệu một biến kích thước hoặc đệm đầy đủ/trống cờ; những điều này thường được viết bởi cả nhà sản xuất và người tiêu dùng và do đó sẽ cung cấp cho bạn một vấn đề.

Tôi thường sử dụng bộ đệm vòng cho người rút thăm này. Bài học quan trọng nhất mà tôi đã học được là một bộ đệm vòng của không bao giờ có thể chứa nhiều hơn các phần tử. Bằng cách này, đầu số đầuđuôi được viết bởi nhà sản xuất tương ứng với người tiêu dùng.

Extension for lớn/khối kích thước biến Để sử dụng bộ đệm trong một môi trường thời gian thực, bạn có thể sử dụng hồ bơi bộ nhớ (thường có sẵn ở dạng tối ưu trong thời gian thực hệ điều hành) hoặc tách phân bổ từ việc sử dụng. Cái thứ hai phù hợp với câu hỏi, tôi tin.

extended queue http://img16.imageshack.us/img16/8725/extq.gif

Nếu bạn cần trao đổi khối lượng lớn, tôi đề nghị sử dụng một hồ bơi với khối đệm và giao tiếp con trỏ đến bộ đệm sử dụng một hàng đợi. Vì vậy, sử dụng một hàng đợi thứ 3 với con trỏ đệm. Bằng cách này, việc phân bổ có thể được thực hiện trong ứng dụng (nền) và phần thời gian thực của bạn có quyền truy cập vào một lượng bộ nhớ thay đổi.

Application

while (blockQueue.full != true) 
{ 
    buf = allocate block of memory from heap or buffer pool 
    msg = { .... , buf }; 
    blockQueue.Put(msg) 
} 

Producer: 
    pBuf = blockQueue.Get() 
    pQueue.Put() 

Consumer 
    if (pQueue.Empty == false) 
    { 
     msg=pQueue.Get() 
     // use info in msg, with buf pointer 
     // optionally indicate that buf is no longer used 
    } 
+0

Tôi không làm theo lời giải thích ở đây. Cần một số hiệu đính. – thebretness

+0

Cảm ơn bạn đã dành rất nhiều thời gian cho việc này. Thiết kế của bạn bị một thực tế là nếu người tiêu dùng không chạy, các nhà sản xuất và cho ăn chủ đề sẽ bị đói, như cho một ringbuffer, nhưng tiêu thụ tất cả các bộ nhớ heap. – moala

+0

Tôi vừa giải thích phần thời gian thực; thiết kế thời gian thực là vấn đề phức tạp mà tôi đang làm việc hàng ngày. Tùy thuộc vào cách bạn xử lý xử lý ngoại lệ của mình (máy khách không chạy, v.v.). Tôi không thể quyết định cho bạn (loại bỏ dữ liệu, thực hiện xử lý ngoại lệ hoặc chặn). Vì đây là các bộ đệm vòng, bạn có thể kiểm soát số lượng các phần tử đủ cho độ trễ dự kiến ​​của tác vụ nền. – Adriaan

0

Dưới đây là một. Các khóa là có ba bộ đệm và người đọc dự trữ bộ đệm mà nó đang đọc. Người viết viết cho một trong hai bộ đệm khác. Nguy cơ va chạm là tối thiểu. Thêm vào đó, điều này mở rộng. Chỉ cần làm cho mảng thành viên của bạn một phần tử dài hơn số lượng người đọc cộng với số lượng người viết.

class RingBuffer 
{ 
    RingBuffer():lastFullWrite(0) 
    { 
    //Initialize the elements of dataBeingRead to false 
    for(unsigned int i=0; i<DATA_COUNT; i++) 
    { 
     dataBeingRead[i] = false; 
    } 
    } 

    Data read() 
    { 
    // You may want to check to make sure write has been called once here 
    // to prevent read from grabbing junk data. Else, initialize the elements 
    // of dataArray to something valid. 
    unsigned int indexToRead = lastFullWriteIndex; 
    Data dataCopy; 
    dataBeingRead[indexToRead] = true; 
    dataCopy = dataArray[indexToRead]; 
    dataBeingRead[indexToRead] = false; 
    return dataCopy; 
    } 

    void write(const Data& dataArg) 
    { 
    unsigned int writeIndex(0); 

    //Search for an unused piece of data. 
    // It's O(n), but plenty fast enough for small arrays. 
    while(true == dataBeingRead[writeIndex] && writeIndex < DATA_COUNT) 
    { 
     writeIndex++; 
    } 

    dataArray[writeIndex] = dataArg; 

    lastFullWrite = &dataArray[writeIndex]; 
    } 

private: 
    static const unsigned int DATA_COUNT; 
    unsigned int lastFullWrite; 
    Data dataArray[DATA_COUNT]; 
    bool dataBeingRead[DATA_COUNT]; 
}; 

Lưu ý: Cách viết ở đây, có hai bản để đọc dữ liệu của bạn. Nếu bạn chuyển dữ liệu của bạn ra khỏi chức năng đọc thông qua một đối số tham chiếu, bạn có thể cắt giảm xuống một bản sao.

+0

Điều gì sẽ xảy ra nếu * lastFullWriteIndex * trong * read * sẽ được thay đổi bởi * write * nếu * write * sẽ được gọi ở giữa * read *? Sau đó, bạn sẽ có hai trường hợp * dataBeingRead * được đặt thành * true *. – werewindle

+0

Bắt tốt. Đã sửa. – thebretness

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