2011-07-05 21 views
12

Có phải std :: random_shuffle threadsafe? Tôi đoán không phải vì rand thường xuyên() không phải là threadsafe. Nếu đó là trường hợp, làm thế nào tôi sẽ sử dụng rand_r với random_shuffle để tôi có thể cung cấp cho mỗi thread một hạt giống duy nhất. Tôi đã nhìn thấy các ví dụ về việc sử dụng các trình tạo ngẫu nhiên tùy chỉnh với random_shuffle, nhưng nó vẫn chưa rõ ràng với tôi.Chuỗi chủ đề random_shuffle có an toàn không? và sử dụng rand_r nếu nó không phải là

Cảm ơn.

+4

Nói chung, bạn phải làm cho các giả định rằng * gì * trong thư viện C++ là chỉ an toàn trừ khi tài liệu có quy định khác. –

+1

Ngoài ra, 'chủ đề an toàn' là một thuật ngữ quá tải. Một số thuật toán chỉ an toàn nếu chúng hoạt động trên dữ liệu an toàn. Một số là an toàn trên các chủ đề miễn là chỉ có 1 nhà văn, và hầu hết không thể đảm bảo điều đó. Nói chung, khi quyết định cái gì là an toàn (nghĩa là đúng), nó đòi hỏi bạn chỉ định các yêu cầu đọc/ghi khác nhau. – Kylotan

+0

Chỉ cần làm rõ, tôi muốn làm các xáo trộn trên các danh sách khác nhau song song.Vì vậy, tôi không quan tâm đến các cuộc đua trong cấu trúc dữ liệu, chỉ là việc tạo ra các số ngẫu nhiên cho việc trộn. – Mark

Trả lời

4

Để sử dụng rand_r với std::random_shuffle, bạn sẽ cần phải viết một (khá tầm thường) wrapper. Trình tạo số ngẫu nhiên mà bạn chuyển đến random_shuffle cần phải chấp nhận tham số chỉ định phạm vi số được tạo, trong đó rand_r thì không.

wrapper của bạn sẽ giống như thế này:

class rand_x { 
    unsigned int seed; 
public: 
    rand_x(int init) : seed(init) {} 

    int operator()(int limit) { 
     int divisor = RAND_MAX/(limit+1); 
     int retval; 

     do { 
      retval = rand_r(&seed)/divisor; 
     } while (retval > limit); 

     return retval; 
    }   
}; 

Bạn muốn sử dụng nó với random_shuffle cái gì đó như:

std::random_shuffle(whatever.begin(), whatever.end(), rand_x(some_seed)); 
+0

Cảm ơn. Seed phải là một int không dấu. Ngoài ra, tại sao có một vòng lặp while làm trái ngược với trả về rand_r (& seed)% limit? Có cái gì đó tinh tế mà tôi đang thiếu? – Mark

+0

@Mark: Rất tiếc - đã sửa. Về vòng lặp, hãy xem xét cách bạn chia 10 kẹo bằng nhau giữa 3 trẻ em (và bạn không thể phá vỡ một kẹo thành từng miếng). Câu trả lời là bạn không thể - bạn chỉ có thể phân phối 9 trong số họ. Điều này về cơ bản là làm điều tương tự để phân chia kẹo 'RAND_MAX' giữa trẻ em' giới hạn' và loại bỏ bất kỳ phần thừa nào để tất cả các cọc đều bằng nhau. Sử dụng '% limit' (hoặc'/divisor') bởi chính nó * không thể * chia các số đồng đều trừ khi 'RAND_MAX' xảy ra là bội số chính xác của' giới hạn' (và 'RAND_MAX' thường là số nguyên tố, vì vậy nó không phải là chính xác bội số của * bất kỳ * có ý nghĩa 'giới hạn'). –

+0

Mặc dù tôi đồng ý với mọi thứ mà Jerry đã nói, người ta có thể lập luận rằng nếu bạn đang sử dụng 'rand_r', thì bạn không có quyền giả định rằng nó có phân phối đồng đều để bảo toàn. Nhưng ít nhất theo cách này, * if * 'rand_r' là tốt, sau đó shuffle của bạn là tốt quá, bạn không giới thiệu bất kỳ thiên vị mới. –

3

Bạn cần cung cấp chức năng trình tạo số ngẫu nhiên hoặc đối tượng functor lấy giá trị tích phân và trả về giá trị khác của một số loại không thể tách rời sẽ không tràn các giới hạn của vùng chứa mà trình lặp mà bạn đã chuyển vào hàm lặp qua. Cũng trong trường hợp của một đối tượng functor, nó phải thực hiện các operator() để nó có thể được gọi là một hàm. Vì bạn cần một trình tạo số ngẫu nhiên an toàn thread, sử dụng srandrand từ cstdlib là một ý tưởng tồi ... bạn nên tạo một số đối tượng functor thực hiện trình tạo số ngẫu nhiên an toàn chủ đề hoặc trình tạo số ngẫu nhiên không triển khai các biến có thể truy cập trên toàn cầu để mọi thứ vẫn giữ nguyên lưu trữ cục bộ. Ví dụ, một cách có thể hoạt động là bạn có một loại trình tạo số ngẫu nhiên mà bạn đã nhận được từ một thư viện khác. đối với các trình vòng lặp truy cập ngẫu nhiên, thuật toán random_shuffle sử dụng. Bây giờ tùy thuộc vào những gì thư viện bạn sử dụng, bạn functor có thể trông giống như sau:

class my_rand_gen 
{ 
    private: 
     random_gen_type random_range_gen; 
     int min; 
     int max; 

    public: 
     my_rand_gen(const random_gen_type& gen, int min_range, int max_range): 
        random_range_gen(gen), min(min_range), max(max_range) {} 

     int operator()(int value) 
     { 
      //ignore the input value and use our own defined range 
      //returns a value between min and max 
      return random_range_gen(min, max); 
     } 
}; 

Bây giờ bạn có thể gọi các thuật toán như:

random_shuffle(my_vector_start_iter, my_vector_end_iter, 
       my_rand_gen(rand_generator_lib, 
          vector_start_index, 
          vector_end_index)); 

và nó sẽ shuffle vector ở giữa đầu và các trình vòng lặp kết thúc cho vectơ của bạn mà không làm tràn các giới hạn của vec-tơ ... nói cách khác, nó sẽ chỉ sử dụng các giá trị cho shuffle giữa vector_start_indexvector_end_index.

+0

Các lớp' 'mới sẽ là một khởi đầu tốt cho điều đó - bạn có thể có một PRNG cho mỗi luồng. –

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