2013-07-02 36 views
8

Tôi hiện đang nghiên cứu một vấn đề mô phỏng một mô hình Công nhân sản xuất mở rộng. Trong vấn đề này có 3 công nhân và 3 công cụ có sẵn, và cho công nhân làm việc họ cần 2 công cụ (và vật liệu nhưng những thứ đó không liên quan). Nếu có> = 2 công cụ trong hầm, nhân viên sẽ lấy 2. Khác, họ sẽ đợi trên biến điều kiện sẽ được báo hiệu khi có> = 2.C++ 11 Chủ đề: Nhiều chủ đề đang chờ trên biến điều kiện

Điều này là tốt với 2 công nhân: một người sẽ làm việc sau đó trả lại công cụ cho hầm, và công nhân chờ đợi khác sẽ được đánh thức và có 2 công cụ. Vấn đề là, với 3 công nhân, sẽ luôn có một người chết đói để có được các công cụ.

Sau một số thử nghiệm, tôi nhận thấy rằng các chuỗi đang chờ biến điều kiện được cấu trúc theo dạng ngăn xếp. Có cách nào có thể làm cho nó xếp hàng đợi? (1 lần chờ đợi, 2 lần chờ đợi và 3 lần chờ đợi khi 1 được đánh thức và muốn thực hiện một thiết bị khác, anh phải đợi sau 2 và 3.)

Dưới đây là một đầu ra mẫu. Mã quá dài nên tôi sẽ đăng nó nếu nó thực sự cần thiết. Có 3 chủ đề công nhân và 1 công cụ mutex. Ai đói là khác nhau chạy.

1 Tools taken. Remaining: 1 
2 Waiting on tools... 
3 Waiting on tools... 
1 Operator Product made. Tools returned. Tools now:3 
3 Tools taken. Remaining: 1 
1 Waiting on tools... 
3 Materials returned for switch. 
3 Operator Product made. Tools returned. Tools now:3 
1 Tools taken. Remaining: 1 
3 Waiting on tools... 
1 Materials returned for switch. 
1 Operator Product made. Tools returned. Tools now:3 
3 Tools taken. Remaining: 1 
1 Waiting on tools... 
3 Materials returned for switch. 
3 Operator Product made. Tools returned. Tools now:3 
1 Tools taken. Remaining: 1 
3 Waiting on tools... 
1 Materials returned for switch. 
1 Operator Product made. Tools returned. Tools now:3 
3 Tools taken. Remaining: 1 
1 Waiting on tools... 
3 Materials returned for switch. 
3 Operator Product made. Tools returned. Tools now:3 
1 Tools taken. Remaining: 1 
3 Waiting on tools... 
1 Materials returned for switch. 
... 

(Như bạn có thể thấy 2 không bao giờ được các công cụ ...)

Cập nhật: 2013/07/05 Tôi đã thêm một số mã.

int tools = 3; //global 
string last; //current last product on output buffer 
mutex toolsMutex; 
mutex matSearchMutex; 

int main(){ 
//Initializing Producers 
    Producer prod1(1); 
    Producer prod2(2); 
     Producer prod3(3); 



    thread p1(processor,1); 
    thread p2(processor,2); 
    thread p3(processor,3); 

    p1.detach(); 
    p2.detach(); 
    p3.detach(); 

    while(true){//forever running 

    } 

    return 0; 
} 

Processor:

//Processor method 
void processor(int i){ 
    srand(time(NULL)); 

    while (true){ //forever running 


    bool hasTools = false; 
    bool productMade = false; 
    while (productMade == false){ //while product has yet to be made. 
     //choose what to make... 



     if (hasTools == false){ 
      thread matT(getMaterials,whatToMake); 
      thread toolT(getTools,i); 
      toolT.join();   
      matT.join(); 
      hasTools = true; 
     } 
     else{ //tools acquired but no materials 
      thread matT(getMaterials,whatToMake); 
      matT.join(); 
     } 

     if (recordedLast.compare(last) != 0){ 

      //return materials and acquire new ones the next run 

      continue; 
     } 
     else { 
      makeProduct(whatToMake); 
      unique_lock<mutex> locker(toolMutex); 
      tools = tools + 2; 
      cout << i << " Operator Product made. Tools returned. Tools now:" << tools << endl; 
      productMade = true; 
      if (tools >=2) toolsCV.notify_one(); 
     } 

    //done processing 

    } 


} 

} 

makeProducts:

void makeProduct(int i){ 
    unique_lock<mutex> mainMatLock(matSearchMutex); 
    // make product according to i 
    this_thread::sleep_for(chrono::milliseconds(rand() % 1000 + 10)); 
} 

getTools:

void getTools(int i){ 
    unique_lock<mutex> locker(toolMutex); 
    if (tools <2){ 
     cout << i << " Waiting on tools..." << endl; 
     toolsCV.wait(locker);} 
    tools = tools - 2;//tools acquired 
    cout << i <<" Tools taken. Remaining: " << tools << endl; 

} 

Nhờ có những người đã trả lời. Tôi sẽ cố gắng thực hiện một hàng chờ đợi tối nay bằng cách sử dụng nhiều biến điều kiện.

(PS Có một số cách tốt hơn để làm mã định dạng ở đây trên Stack Overflow? Khác với bốn không gian ...

+0

Tại sao bạn không đăng mã thực của mình? Bạn đã thử phát sóng trên biến điều kiện (so với tín hiệu) chưa? Bạn chưa chỉ định bất kỳ điều gì về môi trường của mình, nhưng có thể muốn xem qua http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_08_04_01 –

+1

_ "Có cách nào tốt hơn để làm mã không định dạng ở đây trên Stack Overflow? "_ Nhập mã mà không có dấu cách sau đó làm nổi bật toàn bộ khối mã và nhấn Ctrl-K hoặc nhấn nút ** {} ** trên thanh công cụ phía trên hộp chỉnh sửa –

Trả lời

9

std::condition_variable không chỉ định chuỗi chờ nào được đánh thức khi bạn gọi notify_one. Do đó, bạn nên viết mã mà không quan tâm thread nào được đánh thức. Mẫu tiêu chuẩn là bất kỳ luồng nào được đánh thức, luồng đó phải thực hiện công việc cần được thực hiện.

Nếu bạn yêu cầu các chủ đề được đánh thức theo thứ tự cụ thể, thì hãy sử dụng một cơ chế khác. Bạn có thể, ví dụ, có một std::condition_variable riêng biệt cho mỗi luồng, và sau đó đặt các chuỗi trong một hàng đợi khi chúng cần các công cụ. Với tư cách là một nhánh trong các công cụ, nó có thể báo hiệu biến điều kiện tương ứng với luồng ở phía trước hàng đợi. Chủ đề đó sau đó sẽ được đánh thức, và những người khác sẽ vẫn ngủ (modulo spurious wake-up).

3

Khi có một số đề chờ đợi vào một điều kiện, trình tự trong đó họ được đánh thức (notify_all) hoặc đó là một trong đánh thức (notify_one) là không xác định Nếu bạn cần một số loại đặt hàng, bạn cần phải sử dụng notify_all, và thực hiện nó mình bạn có thể giữ một danh sách các các chủ đề chờ đợi:.. trước chờ (nhưng sau khi có được mutex), hãy đẩy id luồng lên kết thúc hàng đợi. "chủ đề này ở trước hàng đợi và các công cụ cần thiết có sẵn". Khi bạn nhận được các công cụ , hãy xóa id khỏi mặt trước của hàng đợi và gọi lại notify_all.

0

Một cách tiếp cận có thể là sử dụng Semaphore đầy đủ được chia sẻ giữa các chủ đề thay vì biến điều kiện. Bằng cách đó, bạn có thể chờ đợi một số lượng cụ thể.

#include <mutex> 
#include <thread> 
#include <condition_variable> 

using std::mutex; 
using std::condition_variable; 

class Semaphore 
{ 
public: 
    /** 
    * Construct a counting semaphore with an initial value 
    * @param cnt The value of the initial semaphore count 
    */ 
    Semaphore(unsigned int cnt); 

    /** 
    * acquire a semaphore count 
    * @param numRes The number of count ressources to acquire 
    */ 
    void acquire(unsigned int numRes = 1); 

    /** 
    * try to acquire a semaphore count. 
    * @param numRes The number of count ressources that the method tries to acquire 
    * @return true, if numRes could be aquired 
    *   false, otherwise 
    */ 
    bool tryAcquire(unsigned int numRes = 1); 

    /** 
    * release one semaphore cnt 
    * @param numRes The number of count ressources to release 
    */ 
    void release(unsigned int numRes = 1); 

private: 
    unsigned int cnt; 
    mutex mut; 
    condition_variable cond; 
}; 

Thực hiện trông giống như:

void Semaphore::acquire(unsigned int numRes) 
{ 
    unique_lock<mutex> lock(mut); 
    while (cnt < numRes) 
    { 
     cond.wait(lock); 
    } 

    cnt-=numRes; 
} 

bool Semaphore::tryAcquire(unsigned int numRes) 
{ 
    unique_lock<mutex> lock(mut); 
    if (cnt>=numRes) 
    { 
     cnt -= numRes; 
     return true; 
    } 
    return false; 
} 

void Semaphore::release(unsigned int numRes) 
{ 
    { 
     unique_lock<mutex> lock(mut); 
     cnt += numRes; 
    } 
    // notify <numRes> waiting entities 
    for (unsigned int i = 0; i<numRes; ++i) 
    { 
     cond.notify_one(); 
    } 
} 
1

Vấn đề thực sự ở đây là nếu bạn có đề người lao động và số lượng hạn chế các nguồn lực cần thiết, bạn không nên quan tâm những chủ đề thực sự được kích hoạt, bạn chỉ nên chăm sóc rằng công việc được thực hiện. Sự khác biệt duy nhất ở đây là trong quá trình ghi nhật ký. Số lượng các chủ đề mà bạn đã xác định là số luồng có thể chạy song song, được giới hạn bởi các tài nguyên cho một luồng.

Nếu điều này không phù hợp với bạn, thì bạn cần tự mình thực hiện hành động như được giải thích trong các câu trả lời khác.