Pytanie c ++ 11 atomizery międzyprocesowe i muteksy


Mam program linuksowy, który spawnuje kilka procesów (fork) i komunikuje się poprzez POSIX Shared Memory. Chciałbym, aby każdy proces przydzielał identyfikator (0-255). Moją intencją jest umieszczenie bitvektora w regionie pamięci współużytkowanej (zainicjowanym do zera) i porównanie atomowe oraz zamiana bitu w celu przydzielenia identyfikatora.

Czy jest to sposób przyjazny dla c ++ 11? Czy mogę utworzyć atomowy bitset? Czy mogę używać muteksu w procesach? W jaki sposób zapewnić, aby konstruktory były wywoływane raz i tylko raz we wszystkich procesach?


15
2017-10-31 15:15


pochodzenie


fork zwraca pid procesu potomnego do procesu nadrzędnego, dlaczego nie użyć go zamiast generowania kolejnego? Albo nie rozumiem twojego pytania
@NicolBolas Wziąłem mój problem i wybrałem minimalne niezbędne informacje, aby zadać pytanie, które pozwoli mi rozwiązać mój problem. Nie szukam ludzi, którzy mogliby zmienić problem. Mogłem stworzyć arbitralny problem z synchronizacją i zapytać go o pamięć współdzieloną posix w różnych procesach, a pytanie nadal trwa. Jeśli ci pomoże, udawaj, że pytam o wspólną strukturę danych i o to, jak działają muteksy lub atomy C ++. - dschatz
@dschatz: I tak, masz klasyczne pytanie XY. - Nicol Bolas
@dschatz: "Pytam ogólnie, jak muteksy c ++ 11 i atomics działają w różnych procesach (Hej, tytuł pasuje!)."W takim razie nie powinieneś podawać bardzo konkretnego, wymyślnego i bezużytecznego przykładu jako pierwszego akapitu pytania ogólnego, jeśli powiedziałeś to jako" Chcę wiedzieć, jak prymitywy wątkowania C ++ 11 działają w różnych procesach. Na przykład, blah ", wtedy jasne byłoby, że pytanie było ogólne, ogólny tytuł z konkretnym wewnętrznym pytaniem jest wspólny dla SO Tak bardzo, że generalnie zignorowałem tytuły, gdy tylko przeczytałem pytanie. - Nicol Bolas
C ++ 11 nie ma funkcji między procesami. Zwiększenie :: Interprocess może mieć dla ciebie kilka narzędzi do wykorzystania w tym przypadku. - Christopher


Odpowiedzi:


C ++ 11 prymitywów gwintowania (muteksy, atomiki, itp.) Są gwintowanie prymitywy. Nie wiedzą nic o procesach i nie są środkiem do osiągnięcia komunikacji między procesami.

Ponieważ standard C ++ 11 nie wspomina o procesach lub komunikacji międzyprocesowej, zachowanie takich prymitywów po umieszczeniu w pamięci współdzielonej procesowo (plik odwzorowany w pamięci, pewien rodzaj pozaformalnej zmapowanej globalnie pamięci itp. ) jest niezdefiniowany.


13
2017-10-31 17:19



[atomics.lockfree] zawiera "[Uwaga: Operacje, które są blokowane, powinny być wolne od adresów, to znaczy operacje atomowe w tej samej lokalizacji pamięci przez dwa różne adresy będą komunikować się atomowo. Implementacja nie powinna zależeć od stan procesu - ograniczenie to umożliwia komunikację za pomocą pamięci, która jest odwzorowywana w procesie więcej niż jeden raz oraz przez pamięć współużytkowaną między dwoma procesami. - Jeffrey Yasskin
Drogi @Nicol Bolas, twoja odpowiedź jest świetna, ale nie mogę znaleźć nigdzie ani żadnych książek na ten temat, więc nadal mam pewne wątpliwości dotyczące używania mutex C ++ 11 we wspólnej pamięci. (jak wiem, pthread mutex jest ok, jeśli używasz PTHREAD_PROCESS_SHARED) - Trung Nguyen
Naprawdę chciałbym, żeby to było zawarte w referencjach takich jak en.cppreference.com/w/cpp/thread/mutex  - sage


Możesz użyć muteksu wewnątrz bloku pamięci współdzielonej, ale muteks musi być zadeklarowany jako SHARED, dlatego też nie jest niczym niezwykłym, używając muteksów wewnątrz współużytkowania pamięci, możesz stworzyć własną klasę, jest to bardzo proste:

class Mutex {
private:
    void *_handle;
public:
    Mutex(void *shmMemMutex,  bool recursive =false, );
    virtual ~Mutex();

    void lock();
    void unlock();
    bool tryLock();
};

Mutex::Mutex(void *shmMemMutex, bool recursive)
{
    _handle = shmMemMutex;
    pthread_mutexattr_t attr;
    ::pthread_mutexattr_init(&attr);
    ::pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
    ::pthread_mutexattr_settype(&attr, recursive ? PTHREAD_MUTEX_RECURSIVE_NP : PTHREAD_MUTEX_FAST_NP);

    if (::pthread_mutex_init((pthread_mutex_t*)_handle, &attr) == -1) {
        ::free(_handle);
        throw ThreadException("Unable to create mutex");
    }
}
Mutex::~Mutex()
{
    ::pthread_mutex_destroy((pthread_mutex_t*)_handle);
}
void Mutex::lock()
{
    if (::pthread_mutex_lock((pthread_mutex_t*)_handle) != 0) {
        throw ThreadException("Unable to lock mutex");
    }
}
void Mutex::unlock()
{
    if (::pthread_mutex_unlock((pthread_mutex_t*)_handle) != 0) {
        throw ThreadException("Unable to unlock mutex");
    }
}
bool Mutex::tryLock()
{
    int tryResult = ::pthread_mutex_trylock((pthread_mutex_t*)_handle);
    if (tryResult != 0) {
        if (EBUSY == tryResult) return false;
        throw ThreadException("Unable to lock mutex");
    }
    return true;
}

4
2017-11-11 14:35