2014-10-03 3 views
1

Я всегда находил синхронизированное заявление Java, чтобы быть чистым способом сделать семафор, как замок и отпирает:Возможно ли иметь Java как инструкции синхронизации в C, C++?

public void addName(String name) { 
    synchronized(this) { 
     lastName = name; 
     nameCount++; 
    } 
    nameList.add(name); 
} 

Хотя основная концепция мониторов, используемых в Java и PTHREAD мьютексов разные, PTHREAD мьютексов в их наиболее основной часто используются как:

void addName(char* name) { 

    int status = -1; 

    status = pthread_mutex_lock(this->lock); 
    if (status == 0) { 
     this->lastName = name; 
     this->nameCount++; 
     pthread_mutex_unlock(this->lock); 
    } 

    nameList->add(name); 
} 

Я понимаю, что приведенный выше код не реально использовать возможности PTHREAD мьютексы. Он также не обрабатывает все сценарии ошибок. Однако это, вероятно, самый распространенный способ использования мьютексов pthread. Сказать, что я думаю, что было бы неплохо иметь более чистые идиомы для таких синхронизаций:

public void addName(char* name) { 
    synchronized(this->lock) { 
     this->lastName = name; 
     this->nameCount++; 
    } 
    nameList.add(name); 
} 

Итак, можно сделать это в C, C++?

ответ

0

Мы можем иметь что-то вроде:

#define SYNC_R rwlock_rd 
#define SYNC_W rwlock_wr 
#define SYNC_S spin_ 
#define SYNC_M mutex_ 

#define pthread_rwlock_wrunlock pthread_rwlock_unlock 
#define pthread_rwlock_rdunlock pthread_rwlock_unlock 

#define __SYNC_X__(lockObj, lockType) for(int __sync_status__=!pthread_##lockType##lock(lockObj); __sync_status__ ; pthread_##lockType##unlock(lockObj), __sync_status__=0) 

#define __SYNC_M__(lockObj) for(int __sync_status__=!pthread_mutex_lock(lockObj); __sync_status__ ; pthread_mutex_unlock(lockObj), __sync_status__=0) 

#define __SYNCALIAS__(_1, _2, NAME, ...) NAME 

#define __SYNC__(...) __SYNCALIAS__(__VA_ARGS__, __SYNC_X__, __SYNC_M__)(__VA_ARGS__) 

#define synchronized(...) __SYNC__(__VA_ARGS__) 

Это позволяет нам иметь две разновидности блоков синхронизации - Первый раз для мьютексы:

synchronized(this->lock) 
// ==> __SYNC__(this->lock) 
// ==> __SYNCALIAS__(this->lock, __SYNC_X__, __SYNC_M__)(this->lock) 
// ==> __SYNC_M__(this->lock) 
// ==> for(int __sync_status__=!pthread_mutex_lock(lockObj); __sync_status__ ; pthread_mutex_unlock(lockObj)) 
{ 
    this->lastName = name; 
    this->nameCount++; 
} 

В качестве альтернативы можно использовать rwlocks, спин-блоки или даже мьютексы с дополнительным параметром: -

synchronized(this->rwlock, SYNC_W) 
// ==> __SYNC__(this->rwlock, rwlock_wr) 
// ==> __SYNCALIAS__(this->rwlock, rwlock_wr, __SYNC_X__, __SYNC_M__)(mm, rwlock_rd) 
// ==> __SYNC_X__(this->rwlock, rwlock_wr) 
// ==> for(int __sync_status__=!pthread_rwlock_wrlock(lockObj); __sync_status__ ; pthread_rwlock_wrunlock(lockObj)) 
// ==> for(int __sync_status__=!pthread_rwlock_wrlock(lockObj); __sync_status__ ; pthread_rwlock_unlock(lockObj)) 
{ 
    this->lastName = name; 
    this->nameCount++; 
} 

Проблема в том, что он не обрабатывает сценарии ошибок чисто. Так что, возможно, есть лучший способ сделать это. Хотя этот вариант работает как для C, так и для C++, C++, вероятно, будет иметь собственный бренд решений. Расширения GCC были еще одним проспектом, который я не исследовал.

Также была сделана эталонная реализация по адресу sync.h, sync.c.

+3

Owch, это одна большая куча макросов для такой простой идеи. – matsjoyce

+2

Вы не должны использовать [зарезервированные имена] (http://stackoverflow.com/questions/228783). –

+0

Yep, C++ идет для RAII и, следовательно, не нуждается в макросах. – Deduplicator

0

Я нахожу std::lock_guard() можно использовать по аналогии с функцией синхронной Явы:

class MyType 
{ 
    std::mutex mtx; 

public: 

    void synced_functionA() 
    { 
     std::lock_guard<std::mutex> lock(mtx); 

     // synchronized code 
    } 

    void synced_functionB() 
    { 
     std::lock_guard<std::mutex> lock(mtx); 

     // synchronized code 
    } 
}; 
0

В C++ RAII дает нечто почти столь же аккуратный, как synchronized блок, а с C++ 11 есть стандартная библиотека потоков с помощью этого :

{ 
    std::lock_guard<std::mutex> lock(mutex); 
    lastName = name; 
    nameCount++; 
} // lock released here 

nameList.add(name); 

В C вам необходимо вручную приобрести и освободить замок, как вы описали; это гораздо более простой язык, который не поддерживает автоматическое управление ресурсами.

1

Классический подход - это объект блокировки. Маленький объект, конструктор которого получает мьютекс, и его деструктор освобождает его. Создание объекта блокировки внутри области действия имеет тот же эффект, что и синхронизированная область в Java.

У C++ 11 уже есть все, что необходимо для этого, в форме std::mutex или std::recursive_mutex и std::unique_lock.

следующий подход будет в конечном итоге, в значительной степени тот же результат, как синхронизированного метода в Java:

1) Объявляет std::recursive_mutex класса член

2) приобретают взаимную блокировку в методе.

Пример:

class whatever { 

private: 

    std::recursive_mutex s_mutex; 

// ... The rest of the class definition. 

public: 

// ... 
    void addName(); 

// ... 
}; 

void whatever::addName() 
{ 
    std::unique_lock<std::recursive_mutex> s_lock(s_mutex); 

// ... the rest of the method 
} 

Это не должно быть сделано на всем объеме метода:

void whatever::addName(char* name) 
{ 
    { 
     std::unique_lock<std::recursive_mutex> s_lock(s_mutex); 

     this->lastName = name; 
     this->nameCount++; 
    } 
    nameList.add(name); 
} 

Чтобы подвести итог:

А) Обновление C++, 11, который предлагает версии C++ для мьютексов и блокировок POSIX.

B) Если вы не можете обновить до C++ 11, напишите свои собственные методы мьютекса и блокировки. Вы хотите, чтобы не делать явного pthread_mutex_lock и разблокировать каждый раз, самостоятельно. Легко забыть разблокировать мьютексы, явно, на каком-то пути выхода, и в итоге беспорядок. C++ сделает это за вас, если вы правильно их закроете в методы класса.

+0

+1 и мне жаль, что я не смог бы разобрать это снова, заметив, что методы объекта 'synchronized' Java являются реентерабельными из того же потока. Стандартный 'std :: mutex' зависает при повторном входе из того же потока, тогда как' std :: recursive_mutex' больше связан с тем, как работает синхронизация Java. [Ссылка на синхронизацию Java] (http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html) (см. Нижнюю часть о повторной установке). – WhozCraig

Смежные вопросы