Como posso ter certeza de que há apenas 1 mutex?

votos
2

Estou executando algum código segmento seguro aqui. Eu estou usando um mutex para proteger a seção do código que precisa ser executado somente por apenas 1 thread por vez. O problema que tenho é usar este código, por vezes, eu acabo com 2 objetos mutex. Esta é uma função estática pelo caminho. Como posso ter certeza de apenas 1 objeto mutex é criado ??

/*static*/ MyClass::GetResource()
{

if (m_mutex == 0)
{
// make a new mutex object
m_mutex = new MyMutex();
}

m_mutex->Lock();
Publicado 27/08/2009 em 02:23
fonte usuário
Em outras línguas...                            


5 respostas

votos
12

Basta criar m_mutexfora GetResource(),antes que ele pode nunca ser chamado - isso remove a seção crítica em torno da criação real do mutex.

MyClass::Init()
{
  m_mutex = new Mutex;
}    

MyClass::GetResource()
{
  m_mutex->Lock();
  ...
  m_mutex->Unlock();
}
Respondeu 27/08/2009 em 02:30
fonte usuário

votos
8

A questão é o fio pode ser interrompida depois de verificar se m_mutex é 0, mas não antes de ele cria a exclusão mútua, permitindo que outro thread executar através do mesmo código.

Não atribua a m_mutex imediatamente. Criar um novo mutex, e depois fazer uma atômica comparar troca.

Você não menciona sua plataforma de destino, mas no Windows:

MyClass::GetResource()
{
    if (m_mutex == 0)
    {
        // make a new mutex object
        MyMutex* mutex = new MyMutex();

        // Only set if mutex is still NULL.
        if (InterlockedCompareExchangePointer(&m_mutex, mutex, 0) != 0)
        {
           // someone else beat us to it.
           delete mutex;
        }
    }
    m_mutex->Lock();

Caso contrário, substitua com o que comparar função / swap sua plataforma fornece.

Outra opção é usar a inicialização one-time de apoio, que está disponível no Windows Vista e para cima, ou apenas pré-criar a exclusão mútua, se puder.

Respondeu 27/08/2009 em 02:27
fonte usuário

votos
3

Preguiçoso inicialização mutex não é realmente apropriado para métodos estáticos; você precisa de alguma garantia de que ninguém corre para a inicialização. O seguinte usa o compilador para gerar um mutex estática única para a classe.

/* Header (.hxx) */
class MyClass
{
    ...

  private:
    static mutable MyMutex m_mutex;  // Declares, "this mutex exists, somewhere."
};


/* Compilation Unit (.cxx) */
MyMutex MyClass::m_mutex;            // The aforementioned, "somewhere."

MyClass::GetResource()
{
    m_mutex.Lock();
    ...
    m_mutex.Unlock();
}

Algumas outras soluções exigirá suposições extras de seus colegas programadores. Com o método "chamada init ()", por exemplo, você tem que ter certeza de que o método de inicialização foram chamados, e todo mundo teria que saber esta regra.

Respondeu 27/08/2009 em 02:45
fonte usuário

votos
2

Por que usar um ponteiro de qualquer maneira? Por que não substituir o ponteiro com uma instância real que não requer gerenciamento de memória dinâmica? Isso evita a condição de corrida, e não impõe um acerto de desempenho em cada chamada para a função.

Respondeu 27/08/2009 em 02:35
fonte usuário

votos
0

Uma vez que é apenas para proteger uma seção específica do código, simplesmente declará-la estática dentro da função.

static MyClass::GetResource()
{
    static MyMutex mutex;

    mutex.Lock();
    // ...
    mutex.Unlock();

A variável é uma variável local com duração de armazenagem estática. É expressamente declarado no Standard:

Uma implementação é permitida para efectuar a inicialização precoce de outras variáveis ​​bloco-escopo com duração de armazenamento estático ou fio sob as mesmas condições que uma aplicação tem permissão para inicializar uma variável estaticamente com duração de armazenamento estático ou de fios no âmbito espaço de nomes (3.6.2). Caso contrário, uma tal variável é inicializada pela primeira vez, o controlo passa, através da sua declaração; uma tal variável é considerado inicializado após a conclusão da sua inicialização. Se as saídas de inicialização por lançar uma exceção, a inicialização não está completa, por isso vai ser julgado novamente na próxima controle de tempo entra na declaração. Se o controle entra na declaração simultaneamente enquanto a variável está sendo inicializado, a execução concorrente deverá aguardar a conclusão da inicialização.

A última frase é de particular interesse para você.

Respondeu 20/02/2014 em 13:09
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more