2016-03-25 22 views
1

Çok iş parçacıklı uygulamamda, aynı std::deque kullanan iki iş parçacığım var. Bunlardan biri yazıyor, diğeri ise okur (veri analizi için).Çok Dişli aynı erişim C++

bu hatayı alıyorum:

Deque iterator not dereferencable

DÜZENLEME: Bu benim deque okuma için kullanmak koddur. Hata, if koşulunda daha derin bir yere atılır (at ile deque'e erişiyorum).

for (int i = 0; i <myDeque.size(); i++){ 
    try{ 
     if (myDeque.at(i) > 10){ 
      //do stufff 
     } 
    } 
    catch (...){ 
     cout << "ERROR" << endl; 
    } 
} 

Sanırım, bunun nedeni, bu çok-parçalı deque erişiminden kaynaklanıyor. try-catch bloğu ile hatayı yakalayamıyorum. Bunu yapamam, çünkü daha derin bir "düzlemde" atıldı mı? Bu hatayı düzeltmek için bir olasılık var mı?

+0

'deque' boş mu? –

+0

Hayır, boş değil. – black

+1

Dequeue nesnesine erişimi serileştirmek için herhangi bir senkronizasyon mekanizması (kilit veya muteks gibi) kullanıyor musunuz? Yoksa, yapmalısınız; Paylaşılan veri yapısına erişebilmek için birden fazla iş parçacığı istediğinizde standart çözüm budur. –

cevap

2

Kilitlemeyi mi? Bazı yaygın erişilebilir konumda, beyan bir mutex:

... nondeque stuff ... 
{ 
    std::lock_guard<std::mutex> lock(deque_lock); 
    mydeque.push_back(...); 
} 
... more nondeque stuff... 

ve okurken: tutmak için

... nondeque stuff ... 
{ 
    std::lock_guard<std::mutex> lock(deque_lock); 
    for (const auto& elem : mydeque) { 
     ... do stuff with each element, ideally cheap things to avoid blocking writer ... 
    } 
} 
... more nondeque stuff... 

deneyin ardından sarma okur ve dequeblocks that acquire it yılında yazar

std::mutex deque_lock; 

kilitli blokta minimumda çalışmak; Pahalı bir iş varsa, kilit altındaki değeri kopyalamaya, sonra da diğer iş parçacığını engellemek için kilit olmadan kullanmanıza gerek olabilir.

+0

Engellenen bir belleğe erişmek istediğinde, diğer iş parçacığı ne yapar? Durduruyor mu yoksa basitçe gidip deque yapmak istediği operasyonu "bırakıyor mu?" – black

+0

@black Bu bloke ve devam etmek için muteks üzerinde kilit elde edene kadar bekler. –

+0

@ShadowRanger Teşekkürler! Bu yüzden yazma işlemi için yapacağım (push_back). Bunu okumak için mi yapmalıyım? (Benim sorudaki for döngüsü için). 25 elementi okuyacağım (örnekte sadece 10'u). Bu çok mu uzun? – black

3

Bir sırayla iletişim kurmakta olan bir okuyucu/yazıcı çiftinin son derece basit bir örneği. Bir condition_variable kullanılması çalışmaları yapmak ve yazar bitip bitmediğini olup olmadığı konusunda iletişimi senkronize etmek

Not (okuyucu o kuyruğu boşaltılır ne zaman durdurabilir sinyalini):

#include <iostream> 
#include <thread> 
#include <deque> 
#include <condition_variable> 

std::mutex m; 
std::condition_variable reader_action; 
bool all_written = false; 

std::deque<int> buffer; 

// note: this function is called with the mutex unlocked 
// we have popped i from the buffer 
void handle_read_event(int i) 
{ 
    if (i % 100000 == 0) 
     std::cout << i << std::endl; 
} 

int main() 
{ 
    std::thread writer([]{ 
     for (int i = 0 ; i < 1000000 ; ++i) 
     { 
      { 
       auto lock = std::unique_lock<std::mutex>(m); 
       buffer.push_back(i); 
       lock.unlock(); 
       reader_action.notify_one(); 
      } 
     } 

     auto lock = std::unique_lock<std::mutex>(m); 
     all_written = true; 
     lock.unlock(); 
     reader_action.notify_one(); 
    }); 

    std::thread reader([]{ 
     while(1) 
     { 
      auto lock = std::unique_lock<std::mutex>(m); 
      reader_action.wait(lock, [] { return all_written || (!buffer.empty()); }); 
      if (!buffer.empty()) { 
       int i = buffer.front(); 
       buffer.pop_front(); 
       lock.unlock(); 
       handle_read_event(i); 
      } 
      else if(all_written) 
      { 
       break; 
      } 
     } 
    }); 

    writer.join(); 
    reader.join(); 
    return 0; 
} 

beklenen çıkışı:

0 
100000 
200000 
300000 
400000 
500000 
600000 
700000 
800000 
900000 

biz kuyruğu tahliye ederken yazar beklemek kazanmakta sakınca olmadığına karar verirseniz, biz böylece ikinci iplik uygulamak olabilir:

std::thread reader([]{ 
    while(1) 
    { 
     auto lock = std::unique_lock<std::mutex>(m); 
     reader_action.wait(lock, [] { return all_written || (!buffer.empty()); }); 
     while (!buffer.empty()) { 
      int i = buffer.front(); 
      buffer.pop_front(); 
      handle_read_event(i); 
     } 

     if(all_written) 
     { 
      break; 
     } 
    } 
}); 

... veya amaçlarımıza uygun başka bir strateji.