Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Синхронизация и мьютексы


Автор: nerezus 2.9.2009, 07:16
Код

class InterProcessLock(object):
    def lock(self, delta=0.01):
        while True:
            try:
                self.lockNoWait()
                break;
            except:
                time.sleep(delta)
    
    def __init__(self, name=None):
        self.mutex = None
        if not name:
            name = sys.argv[0]
        self.name = base64.b64encode(name).replace('=','')

    def lockNoWait(self):
        self.mutex = win32event.CreateMutex(None, 0, self.name)
        if win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS:
            self.mutex.Close()
            self.mutex = None
            raise Exception('acquired')

    def unlock(self):
        self.mutex.Close()




Задача: Нужно сделать многопроцессную крит. секцию.
Предполагаю юзать так:
lock = InterProcessLock('name')
lock.lock()
bebebe()
lock.unlock()

Имеются проблемы, причем неизвестно с чем связанные: в нескольких случаях mutex не определяется и не блокирует, а unlock над ним вызывает исключение.

Правильно ли я его реализовал?
Просьба не смотреть на язык, могу сделать и на C, код считать псевдокодом.

Какие альтернативы есть?

Автор: Lazin 2.9.2009, 08:02
если mutex.Close вызывает CloseHandle, то это ошибка, для того, что-бы освободить мьютекс, нужно вызвать ReleaseMutex
вот мой именованный мьютекс, правда на с++
Код

/** @bfeif RAII idiom 
 *  @param TLock - resource type
 *  @param try_enter - try to acquire lock
 *  @param enter - resource acquire
 *  @param leave - resource release
 */
template< 
    class TLock, 
    void (TLock::*enter)() = &TLock::enter, 
    bool (TLock::*try_enter)() = &TLock::try_enter,
    void (TLock::*leave)() = &TLock::leave
>
class advanced_scoped_lock : boost::noncopyable
{
    TLock* lock_;
public:
    advanced_scoped_lock() : lock_(0)
    {
    }
    advanced_scoped_lock(TLock& lock) : lock_(&lock) 
    { 
        (lock_->*enter)(); 
    }
    ~advanced_scoped_lock() 
    { 
        if(lock_)
            (lock_->*leave)(); 
    }
    void acquire(TLock& lock)
    {
        if (lock_)
            (lock_->*leave)(); 
        lock_ = &lock;
        (lock_->*enter)(); 
    }
    bool try_acquire(TLock& lock)
    {
        if (lock_)
            (lock_->*leave)(); 
        lock_ = &lock;
        return (lock_->*try_enter)();
    }
    void release()
    {
        if(!lock_)
            return;
        (lock_->*leave)();
        lock_ = 0;
    }
};


/** @brief Именованый мьютекс
 */
class named_mutex
{
    HANDLE mutex_;///< object handle
public:
    ///Конструктор.
    /** Создает мьютекс
     *  @param name имя объекта. К имени автоматически добавляется Global\programname.
     */
    named_mutex(const char* name) : mutex_(0)
    {
        std::stringstream mname;
        mname << "Global\\programname." << name << std::ends;
        mutex_ = CreateMutex( NULL, FALSE, mname.str().c_str() );
        if (mutex_ == NULL)
        {
            THROW_SYSTEM_ERROR
        }
    }
    ///Деструктор объекта
    ~named_mutex()
    {
        CloseHandle(mutex_);
    }
    ///Захват ресурса (блокирующий)
    /**
     *  Ф-я блокирует вызвавший поток. Захватывает мьютекс.
     */
    void acquire()
    {
        DWORD result = WaitForSingleObject(mutex_, INFINITE);
        if(result != WAIT_OBJECT_0)
        {
            THROW_SYSTEM_ERROR
        }
    }
    ///Освобождение ресурса
    void release()
    {
        if (!ReleaseMutex(mutex_))
        {
            THROW_SYSTEM_ERROR
        }
    }
    ///Неблокирующий захват ресурса
    bool try_acquire()
    {
        DWORD result = WaitForSingleObject(mutex_, 0);
        if(result == WAIT_FAILED)
        {
            THROW_SYSTEM_ERROR
        }
        return (result == WAIT_OBJECT_0);
    }
    typedef advanced_scoped_lock<named_mutex, &named_mutex::acquire, &named_mutex::try_acquire, &named_mutex::release> scoped_lock;
};



Автор: nerezus 3.9.2009, 04:02
Lazin, ага, спс.

Я почти уверен, что внутри mutex реализован правильно.
Меня больше интересует факт блокирования в виде крит. секции:
Правильно ли использовать блокировку по таймеру? (метод lock вверху)

Автор: Lazin 3.9.2009, 08:21
nerezus, честно говоря я вообще не понял, зачем нужно каждый раз в методе lockNoWait - пытаться создать мьютекс, а в методе unlock - удалить, а так-же, почему метод lock работает именно так. Если тебе нужен мьютекс, для синхронизации процессов, то ты:
  • в конструкторе, создаешь именованный мьютекс(CreateMutex)
  • в деструкторе - удаляешь (метод Close)
  • в методе lock - вызываешь WaitForSingleObject, в качестве параметра передаешь свой мьютекс
  • в методе unlock - вызываешь ReleaseMutex

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)