2010-02-15 35 views
6

Khi dữ liệu đệm đôi do chia sẻ giữa các luồng, tôi đã sử dụng hệ thống trong đó một luồng đọc từ một bộ đệm, một luồng đọc từ bộ đệm khác và đọc từ bộ đệm đầu tiên. Vấn đề là, làm thế nào tôi sẽ thực hiện trao đổi con trỏ? Tôi có cần sử dụng một phần quan trọng không? Không có chức năng Interlocked có sẵn mà thực sự sẽ trao đổi các giá trị. Tôi không thể có một chủ đề đọc từ bộ đệm một, sau đó bắt đầu đọc từ bộ đệm hai, ở giữa đọc, đó sẽ là appcrash, ngay cả khi các chủ đề khác không sau đó bắt đầu viết cho nó.Thực hiện hoán đổi con trỏ trong hệ thống đa luồng bộ đệm đôi

Tôi đang sử dụng native C++ trên Windows trong Visual Studio Ultimate 2010 RC.

+0

Ý của bạn là gì: "Không có chức năng khóa liên động nào thực sự trao đổi giá trị."? Tại sao bạn không thể sử dụng các chức năng này? – AndiDog

Trả lời

1

Tại sao bạn không thể sử dụng InterlockedExchangePointer?

chỉnh sửa: Ok, tôi nhận được những gì bạn đang nói bây giờ, IEP không thực sự trao đổi 2 con trỏ trực tiếp với nhau vì nó chỉ mất một giá trị duy nhất bằng cách tham chiếu.

+0

Nếu bạn InterlockedExchangePointer, bạn chỉ có thể thực sự ảnh hưởng đến một con trỏ tại một thời điểm trong một cuộc gọi. Điều đó có nghĩa là để trao đổi tất cả ba con trỏ, tôi cần ba cuộc gọi - để lại một khoảng trống ở giữa. InterlockedExchangePointer thực sự là một từ sai, nó sẽ chỉ thiết lập một con trỏ cho một giá trị đã cho. Tôi hy vọng rằng nó sẽ trao đổi một cặp con trỏ (vì lý do chính xác này). Ngay cả khi nó đã làm việc như thế, tôi vẫn không thể thực sự sử dụng nó mà không cần tạm dừng cả hai chủ đề để làm việc cập nhật, một cái gì đó tôi thực sự muốn tránh. – DeadMG

+0

@DeadMG: 'buf1 = InterlockedExchangePointer (& buf2, buf1);' Nếu bạn gọi nó từ chủ đề hiện đang sử dụng buf1, tôi nghĩ rằng nó sẽ làm những gì bạn muốn. Nhưng tôi không hoàn toàn chắc chắn những gì bạn có ý nghĩa của "tất cả ba con trỏ". – Dan

+0

Tôi có một bộ đệm từ kết xuất, một đến bộ đệm từ logic trò chơi (để cả hai có thể đọc bộ đệm), sau đó một để buffertwo cho logic trò chơi để ghi vào. Vấn đề là toán tử tương đương mà bạn gọi là không nhất thiết phải là nguyên tử - có một khoảng cách giữa InterlockedExchangePointer và buf1 =. Ngay cả khi không có, vẫn không có cơ chế ở đây để đảm bảo rằng tôi không phải là trung gian thông qua kết xuất khi điều này xảy ra. Tôi nghĩ rằng giải pháp mutex đọc-ghi được mô tả trong câu trả lời khác có lẽ là tốt nhất. – DeadMG

6

Sử dụng các phần quan trọng là cách được chấp nhận để thực hiện. Chỉ cần chia sẻ một đối tượng CRITICAL_SECTION giữa tất cả các chủ đề của bạn và gọi EnterCriticalSectionLeaveCriticalSection trên đối tượng đó xung quanh thao tác con trỏ của bạn/bộ đệm đọc/ghi mã. Cố gắng hoàn thành các phần quan trọng của bạn càng sớm càng tốt, để lại nhiều mã bên ngoài các phần quan trọng nhất có thể.

Thậm chí nếu bạn sử dụng thủ thuật trao đổi liên khóa đôi, bạn vẫn cần một phần quan trọng hoặc một thứ gì đó để đồng bộ hóa chủ đề của bạn, vì vậy cũng có thể sử dụng nó cho mục đích này.

+0

Tôi có thể hiểu sai câu hỏi của OP ... Sẽ không có kết quả CRITICAL_SECTION trong việc tuần tự hóa tất cả quyền truy cập vào bộ đệm, do đó đánh bại mục đích có hai trong số chúng? Tôi nghĩ rằng ý tưởng là có hai bộ đệm để mỗi thread có thể có một cái gì đó để làm việc trên cùng một lúc, và đôi khi các bộ đệm sẽ được đổi chỗ. – Dan

+0

Cũng có 2 bộ đệm sẽ vẫn giúp đỡ trong một số trường hợp nhất định.Hãy suy nghĩ về các chuỗi hoán đổi đôi đệm ví dụ. – Blindy

+2

Bạn không giữ nó trong khi truy cập dữ liệu, chỉ trao đổi chúng. – DeadMG

1

Bạn phải xây dựng chức năng của riêng mình để trao đổi các con trỏ sử dụng phần semaphore hoặc phần quan trọng để kiểm soát nó. Sự bảo vệ tương tự cần phải được thêm vào tất cả người dùng của con trỏ, vì bất kỳ mã nào đọc con trỏ đang được sửa đổi là xấu.

Một cách để quản lý việc này là có tất cả các thao tác logic con trỏ hoạt động dưới sự bảo vệ của khóa.

0

Hãy xem, ban đầu tôi đã thiết kế các chủ đề để chúng hoàn toàn không đồng bộ và không yêu cầu bất kỳ đồng bộ hóa nào trong các hoạt động thường xuyên của chúng. Nhưng, vì tôi đang thực hiện các hoạt động trên cơ sở từng đối tượng trong một nhóm luồng, nếu một đối tượng đã cho không thể đọc được vì nó hiện đang được đồng bộ hóa, tôi có thể thực hiện một thao tác khác trong khi chờ đợi. Theo một nghĩa nào đó, tôi có thể chờ đợi và vận hành cùng một lúc, vì tôi có rất nhiều chủ đề để đi xung quanh.

Tạo hai phần quan trọng, một cho mỗi chủ đề. Trong khi hiển thị, hãy giữ phần kết xuất. Các chủ đề khác vẫn có thể làm những gì nó thích cho phần crit khác mặc dù. Sử dụng TryEnterCriticalSection và nếu nó được giữ, sau đó trả về false và thêm đối tượng vào danh sách sẽ được hiển thị lại sau. Điều này sẽ cho phép chúng tôi tiếp tục hiển thị ngay cả khi một đối tượng cụ thể hiện đang được cập nhật. Trong khi cập nhật, giữ cả hai phần crit. Trong khi thực hiện logic trò chơi, hãy giữ phần crit logic trò chơi. Nếu nó đã được tổ chức, đó là không có vấn đề, bởi vì chúng tôi có nhiều chủ đề hơn so với bộ vi xử lý thực tế. Vì vậy, nếu thread này bị chặn, thì một thread khác sẽ chỉ sử dụng thời gian CPU và điều này không cần phải được quản lý.

+0

Tôi không nghĩ rằng bạn có thể duy trì cách tiếp cận không đồng bộ hóa này quá lâu. Rõ ràng là bạn đã đánh vào một bức tường gạch ở đây, và có thể có lỗi kéo dài trong mã của bạn, nhưng nói chung việc cập nhật trạng thái trò chơi yêu cầu một số loại khóa không làm mất hiệu lực trạng thái hiển thị trung gian. – Blindy

+0

Mã nào? : P Tôi chỉ hiển thị một vài đối tượng văn bản đơn giản ngay bây giờ, để kiểm tra thiết kế đa luồng. Tôi thực sự không muốn viết một trình kết xuất đồ họa, sau đó phải quay lại và viết lại nó thành đa luồng. Tôi sẽ xem những gì tôi có thể thực hiện với các khóa hiện tại. – DeadMG

0

Bạn chưa đề cập đến giới hạn nền tảng Windows, nhưng nếu bạn không cần tương thích với các phiên bản cũ hơn Windows Server 2003 hoặc Vista ở phía máy khách, bạn có thể sử dụng chức năng InterlockedExchange64() để trao đổi Giá trị 64 bit. Bằng cách đóng gói hai con trỏ 32 bit vào một cấu trúc cặp 64 bit, bạn có thể hoán đổi hiệu quả hai con trỏ.

Có các biến thể * Liên khóa thông thường trên đó; InterlockedExchangeAcquire64(), InterlockedCompareExchange64(), v.v ...

Nếu bạn cần chạy trên, nói, XP, tôi sẽ đi cho một phần quan trọng. Khi cơ hội tranh chấp thấp, chúng hoạt động khá tốt.

+0

Tôi rất vui vì không chạy trên XP. Nhưng, nó không giải quyết được vấn đề trao đổi các con trỏ giữa render. – DeadMG

4

Điều này nghe có vẻ giống như vấn đề về kiểu người đọc-người viết-mutex đối với tôi.

    [... nhưng tôi chủ yếu làm phát triển nhúng để điều này có thể không có ý nghĩa đối với hệ điều hành Windows. Trên thực tế, trong một hệ điều hành nhúng với một bộ lập lịch dựa trên ưu tiên, bạn có thể thực hiện điều này mà không cần bất kỳ cơ chế đồng bộ nào, nếu bạn đảm bảo rằng hoán đổi là nguyên tử và chỉ cho phép chuỗi ưu tiên thấp hơn trao đổi bộ đệm. ]

Giả sử bạn có hai bộ đệm, B1 và ​​B2, và bạn có hai luồng, T1 và T2. OK nếu T1 đang sử dụng B1 trong khi T2 đang sử dụng B2. Bằng cách "sử dụng" tôi có nghĩa là đọc và/hoặc viết bộ đệm. Sau đó, tại một thời điểm, các bộ đệm cần phải trao đổi để T1 đang sử dụng B2 và T2 đang sử dụng B1. Điều bạn phải cẩn thận là trao đổi được thực hiện trong khi không có luồng nào đang truy cập bộ đệm của nó.

Giả sử bạn chỉ sử dụng một mutex đơn giản. T1 có thể có được mutex và sử dụng B1. Nếu T2 muốn sử dụng B2, nó sẽ phải chờ mutex. Khi T1 hoàn thành, T2 sẽ bỏ chặn và thực hiện công việc của mình với B2. Nếu một trong hai luồng (hoặc một số chủ đề của bên thứ ba) muốn trao đổi các bộ đệm, nó cũng sẽ phải thực hiện mutex. Vì vậy, chỉ sử dụng một mutex serializes truy cập vào bộ đệm - không tốt như vậy.

Nó có thể hoạt động tốt hơn nếu bạn sử dụng mutex của trình đọc giả. T1 có thể thu được khóa đọc trên mutex và sử dụng B1. T2 cũng có thể có được một khóa đọc trên mutex và sử dụng B2. Khi một trong những chủ đề đó (hoặc một chủ đề của bên thứ ba) quyết định đã đến lúc trao đổi bộ đệm, nó sẽ phải ghi một khóa trên mutex. Nó sẽ không thể có được ghi-khóa cho đến khi không có thêm khóa đọc. Tại thời điểm đó, nó có thể trao đổi các con trỏ đệm, biết rằng không ai đang sử dụng một trong hai bộ đệm bởi vì khi có một khóa ghi trên mutex, tất cả các nỗ lực để đọc-khóa sẽ chặn.

+0

Một giải pháp thú vị - khá nhiều giống như tôi đã có trước đó, ngoại trừ sạch hơn. Tuy nhiên, tôi không thể tìm thấy bất kỳ tài liệu nào trên MSDN về các mutexes như vậy. Có phải họ là một phần vốn có của WinAPI, hay tôi sẽ phải tự viết mã cho riêng mình? – DeadMG

+0

Đập tôi. Tôi Googled 'nhà văn đọc mutex windows' và tìm thấy điều này: http://msdn.microsoft.com/en-us/magazine/cc163599.aspx - hữu ích? Google không có 'cửa sổ' để đọc về lý thuyết ... – Dan

+0

Hiện vẫn phải đồng bộ hóa nếu thứ tự của dữ liệu đến quan trọng. Người đọc sẽ phải chờ đợi dữ liệu mới đến trước khi tiếp tục bất kể người đọc/người viết mutexes. –

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