2015-04-22 17 views
13

Làm cách nào để xác định một mảng toàn cầu an toàn với các sửa đổi tối thiểu?Làm thế nào để xác định mảng an toàn thread?

Tôi muốn mọi quyền truy cập vào nó được thực hiện bằng cách sử dụng khối mutex và đồng bộ hóa.

Something như thế này là 'T' sẽ có một số loại (lưu ý rằng từ khoá 'đồng bộ' hiện không định nghĩa AFAIK):

sync Array!(T) syncvar; 

Và mỗi truy cập vào nó sẽ simmilar này:

Mutex __syncvar_mutex; 

    //some func scope.... 
    synchronized(__syncvar_mutex) { /* edits 'syncvar' safely */ } 
+0

Bảo vệ các mảng chính nó là dễ dàng. Bạn chỉ cần tạo một cấu trúc bao bọc với tất cả các hàm và toán tử mảng bị quá tải và nơi tất cả các hàm được đồng bộ hóa. Vấn đề là nhận được các phần tử của chính mảng đó. Việc bảo vệ chúng cũng trở nên phức tạp hơn nhiều, vì ngay sau khi bạn trả về chúng từ một hàm như 'opIndex', chúng không được bảo vệ nữa ... –

+0

Tôi nghĩ đây là những gì' shared (T []) 'được cho là để làm, nhưng dường như không .... –

+0

@ AdamD.Ruppe Tất cả chia sẻ thực sự làm là làm cho nó để biến được chia sẻ trên chủ đề chứ không phải là thread-local. Có một vài trường hợp trình biên dịch sẽ phàn nàn nếu bạn thử và làm việc với chia sẻ được đảm bảo là một vấn đề (trong một số trường hợp liên quan đến hoạt động nguyên tử IIRC), nhưng nó không làm bất cứ điều gì với mutexes hoặc đồng bộ hóa. Tùy ban. Các lớp được đồng bộ hóa là cách được khuyến nghị để xử lý các đối tượng được chia sẻ, nhưng chúng không được triển khai đầy đủ (chỉ các hàm đồng bộ) và bất cứ thứ gì thoát khỏi lớp đó sẽ không được bảo vệ nữa. –

Trả lời

-1

Bạn có ý tưởng đúng. Là một mảng, bạn cần có khả năng chỉnh sửa và lấy thông tin. Tôi khuyên bạn nên xem các tiện ích read-write mutexatomic do Phobos cung cấp. Một hoạt động đọc là khá đơn giản:

  1. synchronize trên mutex.readLock
  2. tải (với atomicLoad)
  3. sao chép các mục ra khỏi synchronize khối
  4. trở lại mục sao chép

Viết nên gần như chính xác như nhau. Chỉ cần syncronize trên mutex.writeLock và thực hiện thao tác cas hoặc atomicOp.

Lưu ý rằng thao tác này sẽ chỉ hoạt động nếu bạn sao chép các phần tử trong mảng trong khi đọc. Nếu bạn muốn tham khảo, bạn cần phải thực hiện đồng bộ hóa bổ sung trên phần tử mỗi khi bạn truy cập hoặc sửa đổi nó.

+0

Tôi tin tưởng hệ thống và tôi cảm thấy nó sẽ thất bại một lần nữa. Nói với tôi khá là bạn nghĩ bạn xứng đáng với danh tiếng '+1' với câu trả lời này? – AnArrayOfFunctions

+0

Tính năng này có hoạt động không? Đó thực sự là tất cả những vấn đề phải không? Nếu bạn nghĩ câu trả lời của tôi đáng giá, thì có. Bạn đã đặt câu hỏi. Tôi đã cho bạn một câu trả lời. Nếu bạn nghĩ rằng nó không đủ, thì chúng ta có thể thấy nó có thể được sửa đổi như thế nào. – Straivers

2

nỗ lực ngây thơ của tôi là để làm một cái gì đó như thế này:

import std.typecons : Proxy: 

synchronized class Array(T) 
{ 
    static import std.array; 
    private std.array.Array!T data; 
    mixin Proxy!data; 
} 

Đáng buồn thay, nó không hoạt động vì https://issues.dlang.org/show_bug.cgi?id=14509

Không thể nói rằng tôi rất ngạc nhiên mặc dù xử lý như automagical của đa luồng thông qua ẩn mutexes là rất unidiomatic trong D hiện đại và khái niệm rất của các lớp học đồng bộ chủ yếu là một relict từ D1 lần.

Bạn có thể thực hiện cùng một giải pháp thủ công, tất nhiên, bằng cách xác định lớp SharedArray riêng với tất cả các phương pháp cần thiết và thêm khóa bên trong phương thức trước khi gọi phương thức riêng tư nội bộ Array. Nhưng tôi đoán bạn muốn một cái gì đó làm việc nhiều hơn trong hộp.

Không thể phát minh ra bất cứ điều gì tốt hơn ngay bây giờ (sẽ nghĩ về nó nhiều hơn), nhưng cần lưu ý rằng nó được khuyến khích trong D để tạo cấu trúc dữ liệu được thiết kế để xử lý truy cập chia sẻ một cách rõ ràng thay vì chỉ bảo vệ dữ liệu bình thường cấu trúc với mutexes. Và, tất nhiên, cách tiếp cận được khuyến khích nhất là không chia sẻ dữ liệu nào cả bằng cách sử dụng thông điệp.

Tôi sẽ cập nhật câu trả lời nếu có điều gì tốt hơn cho tôi.

+0

Không - Tôi muốn thứ gì đó hoạt động và không quá dài. Cảm ơn anyway - Tôi sẽ cho nó một shoot. – AnArrayOfFunctions

0

Bạn có thể bọc mảng bên trong một struct khóa khóa truy cập vào mảng khi chuỗi nhận được mã thông báo và cho đến khi nó thoát ra.

Các wrapper/locker:

  • acquire(): được gọi là trong vòng lặp bằng một sợi dây. Khi nó trả về một con trỏ, luồng này biết rằng nó có mã thông báo khi phương thức trả về một giá trị không null.
  • release(): được gọi bằng một chuỗi sau khi xử lý dữ liệu có quyền truy cập đã được mua trước đó.

.

shared struct Locker(T) 
{ 
    private: 
     T t; 
     size_t token; 
    public: 
     shared(T) * acquire() 
     { 
      if (token) return null; 
      else 
      { 
       import core.atomic; 
       atomicOp!"+="(token, 1); 
       return &t; 
      } 
     } 
     void release() 
     { 
      import core.atomic; 
      atomicOp!"-="(token, 1); 
     } 
} 

và một thử nghiệm nhanh:

alias LockedIntArray = Locker!(size_t[]); 
shared LockedIntArray intArr; 

void arrayTask(size_t cnt) 
{ 
    import core.thread, std.random; 

    // ensure the desynchronization of this job. 
    Thread.sleep(dur!"msecs"(uniform(4, 20))); 

    shared(size_t[])* arr = null; 
    // wait for the token 
    while(arr == null) {arr = intArr.acquire;} 

    *arr ~= cnt;  
    import std.stdio; 
    writeln(*arr); 

    // release the token for the waiting threads 
    intArr.release; 
} 

void main(string[] args) 
{ 
    import std.parallelism; 
    foreach(immutable i; 0..16) 
    { 
     auto job = task(&arrayTask, i); 
     job.executeInNewThread(); 
    } 
} 

Với nhược điểm là mỗi khối hoạt động trên các mảng phải được bao quanh với một Acquire/phát hành cặp.

+0

Vâng - Tôi có thể đạt được điều tương tự bằng cách sử dụng khối 'đồng bộ'. Không phải bất kỳ lợi ích thực sự ở đây? – AnArrayOfFunctions

+0

Mọi người đều đã nói với bạn cách làm, không có cách đơn giản (sửa đổi tối thiểu): bọc một mảng trong một cấu trúc và quá tải các toán tử mà bạn quan tâm.Giải pháp Михаил Страшун sẽ là tốt nhưng như ông nhận thấy, điều này không hoạt động, đó là một khái niệm rất thú vị cho một _solution_ BTW. Bạn có nhận ra rằng bạn có thể đã viết nó (tôi có nghĩa là các wrapper) kể từ ngày? Cũng đừng quên rằng bạn có thể nhận được câu trả lời hay hơn trên NG/forum. Không phải ai cũng thích/sử dụng SO. –

0

Nó khá dễ dàng để làm cho một wrapper xung quanh mảng mà sẽ làm cho nó thread-an toàn. Tuy nhiên, cực kỳ khó để tạo một mảng an toàn không phải là một nút cổ chai đồng thời.

Điều gần nhất mà nói đến cái tâm là lớp CopyOnWriteArrayList Java, nhưng ngay cả khi đó không phải là lý tưởng ...

+0

Tôi biết điều đó nhưng tôi không quan tâm vì đó là chính xác những gì tôi muốn (nút cổ chai đồng thời). Tuy nhiên khi tôi di chuyển xung quanh các câu trả lời - nó không có vẻ 'khá dễ dàng' với tôi. – AnArrayOfFunctions

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