LINUX.ORG.RU

Автоматически освободить мьютекс по выходу из функции (RAII-style) на Си

 ,


1

3

Сабж. Есть C99 (совместимость с компиляторами кроме gcc и clang не нужна, совместимость с libc кроме glibc — тоже); есть самописные мьютексы (mutex_t, mutex_lock(mutex_t *), mutex_unlock(mutex_t *)).

Хочется сделать автоматическое освобождение захваченного мьютекса при выходе из захватившей его функции (типа std::lock_guard в плюсах). Очевидное решение — локальная переменная с адресом мьютекса и __attribute__((cleanup(...))), но хочется сделать красивее, без лишних локальных переменных: ведь адрес мьютекса известен ещё на этапе компиляции.

Возможно?

★★★★★

Последнее исправление: intelfx (всего исправлений: 1)

Сделай макрос типа DECLARE_MUTEX(имя), где будет запрятано все колдовство с созданием мьютекса, объявлением переменной и Т.П.

shkolnick-kun ★★★★★
()
Ответ на: комментарий от shkolnick-kun

Да это-то понятно. Хочется вообще обойтись без лишних локальных переменных. Сказать компилятору «сгенери вот этот вызов с вот этими аргументами перед каждым return'ом».

intelfx ★★★★★
() автор топика

Возможно?

Конечно. Пропатчи компилятор.

tailgunner ★★★★★
()
Ответ на: комментарий от shkolnick-kun

Указатель на мьютекс — глобальная переменная, насколько я понял.

NeXTSTEP ★★
()
Ответ на: комментарий от intelfx

Я просто не могу понять, откуда там может взяться лишняя переменная....

Если ты мьютекс объявляешь локально (auto/static), то для него и объявляй __attribute__((cleanup(mutex_unlock))), в качестве аргумента автоматом будет передан указательна мьютекс.

Если ты его мыделяешь маллоком, то напиши деструктор, в него будет передан двойной указатель...

shkolnick-kun ★★★★★
()
Ответ на: комментарий от Andrey_Utkin

Да тут речь вообще не про _unlocked.

intelfx ★★★★★
() автор топика
Ответ на: комментарий от intelfx

The cleanup attribute runs a function when the variable goes out of scope. This attribute can only be applied to auto function scope variables; it may not be applied to parameters or variables with static storage duration. The function must take one parameter, a pointer to a type compatible with the variable. The return value of the function (if any) is ignored.

If -fexceptions is enabled, then cleanup_function will be run during the stack unwinding that happens during the processing of the exception. Note that the cleanup attribute does not allow the exception to be caught, only to perform an action. It is undefined what happens if cleanup_function does not return normally.

В мануале же четко написано, какой должна быть функция...

shkolnick-kun ★★★★★
()
Ответ на: комментарий от shkolnick-kun

Мьютекс, то бишь одно значение типа uint32_t, — глобальная переменная (на самом деле вообще не важно, он может быть передан как параметр). Чтобы написать attribute cleanup, нужно объявить локальную переменную, в которую положить адрес этого мьютекса. Но это лишняя локальная переменная. Хочу без неё.

intelfx ★★★★★
() автор топика
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от shkolnick-kun

Не, мне никто не даст тащить в CRIU плюсы. Ладно, вопрос закрыт, пойду писать goto, как труъ-кернел-девелоперы.

intelfx ★★★★★
() автор топика

У каждого сишника наступает время, когда хочется извращений. Такой уж язык.

anonymous
()
Ответ на: комментарий от true_admin

Не-а. Написано же в тегах: хочется странного.

intelfx ★★★★★
() автор топика
Ответ на: комментарий от shkolnick-kun

Почему DECLARE_MUTEX(имя),
ТС, имхо, хочет другой макрос:
WITH_MUTEX(mutex,{code_block});

Bad_ptr ★★★★★
()
Ответ на: комментарий от intelfx

Компилятор скорее всего оптимизирует код и в итоге локальная переменная исчезнет (точнее она всегда будет заменяться глобальной), поэтому оверхеда не будет. Главное не описывай её как volatile (сам указатель, значение по указателю вполне может быть таковым), а ещё лучше опиши как const (ну и само собой нельзя ей присваивать нигде кроме объявления).

Вот, например, такой код:

extern int a;

void g(int a, int *b);

void f() {
	int *b = &a;
	*b = 10;
	g(*b, b);
	(*b)++;
}

Превращается в это:

f:
	subq	$8, %rsp
	movl	$a, %esi <-- второй аргумент функции g
	movl	$10, %edi <-- первый аргумент функции g
	movl	$10, a(%rip) <-- присваивание a значения
	call	g
	addl	$1, a(%rip) <-- инкремент переменной a
	addq	$8, %rsp
	ret

Можно заметить, что переменная b испарилась и все обращения идут напрямую к a.

Разумеется, я компилировал с включенными оптимизациями (-O2).

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 2)
Ответ на: комментарий от KivApple

Да, точно, про слонаpointed-to analysis я и забыл. Надо поглядеть, во что превращается код с attribute cleanup.

intelfx ★★★★★
() автор топика

Хочется сделать автоматическое освобождение захваченного мьютекса при выходе из захватившей его функции

сделать .. при выходе из .. функции

то есть a-la atexit, но для функции. Можно вспомнить молодость и пойти путём подмены адреса возврата функции в стеке. Не для всех -Oxx сработает, под каждую архитектуру придётся помуторится и ещё антивирусы могут ругаться..

Но это-же С - тут всё возможно :-)

Но логичнее накатать макрос ONMUTEX(mutex,fun,args...) который захватывает мутекс, искполняет функцию и освобождает мутекс.

MKuznetsov ★★★★★
()

Напиши функцию locked(m, f), которая залочит m, вызовет f(), разлочит m, вернет результат. Вызывай везде locked(m, f).

arturpub ★★
()

Решил уподобиться тому, который захотел писать на C как на Simula и придумал деструкторы? :-)

anonymous
()
Ответ на: комментарий от MKuznetsov

Ты слишком много каких-то костылей понаписал :-) Неужели ты думаешь, что этим можно пользоваться? :-) Сколько же в мире костыле-пейсателей, диву даёшься всякий раз :-)

anonymous
()
Ответ на: комментарий от anonymous

Не ну а чё ваще?

Тут весь тред про костыли...

Вот это:

Но логичнее накатать макрос ONMUTEX(mutex,fun,args...) который захватывает мутекс, искполняет функцию и освобождает мутекс.

Очень даже ничего, и не надо использовать нестандартные расширения языка, в отличии от костыля ОПа...

shkolnick-kun ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.