2016-04-07 18 views
2

C++ 11'de çoklu okuma hakkında bilgi edindim ve bu basit testi denedim ancak çıktı beklediğim gibi değil.std :: mutex std :: cout için düzgün şekilde kilitlenmiyor

#include <thread> 
#include <iostream> 
#include <mutex> 

int main() { 
    auto function = [](int x) { 
     std::mutex m; 
     m.try_lock(); 
     std::cout << "Hello" << x << std::endl; 
     m.unlock(); 
     return; 
    }; 
    std::thread t1(function , 1); 
    std::thread t2(function, 2); 
    std::thread t3(function, 3); 
    std::thread t4(function, 4);  

    t1.join(); 
    t2.join(); 
    t3.join(); 
    t4.join(); 

    std::cin.get(); 
    return 0; 
} 

Ben çıkışı olması bekleniyor:

Hello1 
Hello2 
Hello3 
Hello4 

(belki bu sırayla ancak her Merhaba ve ayrı bir satırda numara)

yerine böyle bir şey var:

HelloHello21 
Hello3 
Hello4 

Ya

HelloHello2 
1 
Hello3 
Hello4 

Muteks'in düzgünce kilitlenmemesi yanında ne yapması gerektiği de, bulmacaları yarıya indiren kişi olan Hello1'dir.

DÜZENLEME: VS2015 yapılan mutlaka muteksi kilitlemez herhangi bir fark (hepsi standarttır olmamalı çünkü?)

+1

Bir fonksiyona yapılan her çağrının yerel değişkenlerin kendi kopyasını aldığını biliyorsunuz, değil mi? Yani bu durumda her iş parçacığının kendi ayrı muteksi vardır. Beklenmeyen bir şekilde, bir muteksin kilitlenmesi diğerlerinin hiçbirini kilitlemez. – immibis

+0

, mutex'in kilitlediğiniz şeyle aynı kapsamda olmasını öneriyor, bu tür hataları önlemek için –

cevap

3

Tüm iş parçacıklarının aynı muteks nesnesine erişmesi gerektiğinden, static kullanmanız gerekir. Ayrıca, unlock()'a ulaşmadan önce try_lock() (veya lock()) bir istisna atılırsa sorunlara neden olur. std::lock_guard<>(), bunu yapmanın çok daha güvenli bir yoludur ve bir işlev dönüşüyle ​​mi yoksa bir istisna yoluyla mı kapsama alanı dışına çıktığınızda yayınlanacağı için önerilir.

fonksiyonunun aşağıdaki revizyon deneyin:

auto function = [](int x) { 
    static std::mutex m; 
    std::lock_guard<std::mutex> mylock(m); 
    std::cout << "Hello" << x << std::endl; 
    return; 
}; 

daha http://en.cppreference.com/w/cpp/thread/lock_guard bakınız. Ayrıca

, ileride muteksin türünü değiştirebilir düşünüyorum (ya da sadece fantezi olmaya çalışıyoruz) Eğer türetilmiş bir şablon türü ile muteksi ayarlayabilirsiniz eğer: Apart neyi Sam zaten gelen

std::lock_guard<decltype(m)> mylock(m); 
+0

teşekkürler! Yine de sadece mutex'i kullanmanın neden işe yaramadığını bilmek isterdim :) –

+1

@StephanosPhilippides 4 ayrı muteks yaptı. Sadece 1 muteks kullanman gerekiyordu. –

2

try_lock() yaparsa. Muteks kilitlenebilir, olmayabilir. Sadece eğer varsa mutex'i kilitlemeye çalışır. Zaten kilitliyse, muteks kilitlenene kadar beklemez, ancak bunun gerçekleştiğine dair bir gösterge döndürür. Bu nedenle, aslında, kodunuz, çıktı, herhangi bir şekilde, şekil, madde veya formda etkili bir şekilde eşitleme yapmaz. Üste |

Muteks gerçekten kilitlemek istiyorsanız, try_lock() yerine lock() kullanın.

DÜZENLEME: ve başka birinin işaret ettiği gibi, kodunuz her iş parçacığı için ayrı bir muteks oluşturur ve bu nedenle bu muteks static'u da oluşturmanız gerekir.