Форум программистов, компьютерный форум CyberForum.ru

реализация ThreadSafe функции - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 9, средняя оценка - 4.67
smithana
2 / 2 / 0
Регистрация: 03.06.2009
Сообщений: 101
24.07.2013, 14:23     реализация ThreadSafe функции #1
Пишу статическую библиотеку функций, на основе которой разрабатывают приложения.
При создании многопоточных приложений на её основе начались проблемы. Думаю, что это связано с тем, что разные потоки мешаются друг другу, заходя в одну и туже функцию библиотеки.

На первое время решил добавить в функции вот такую конструкцию:
C++
1
2
3
4
5
6
7
8
int some_function{
  static UINT32 entryCounter = 0;
  while(entryCounter!= 0) Sleep(1);{
    entryCounter++;
    //тело функции
     entryCounter--;
  }
}
проблемы ушли, но интересно насколько корректный вариант получился и есть ли другие варианты решения данной проблемы?
Спасибо.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.07.2013, 14:23     реализация ThreadSafe функции
Посмотрите здесь:

Реализация функции srcat. C++
C++ Реализация функции принтф
C++ Собственная реализация функции конкатенации
C++ Реализация функции erase()
Реализация функции wait C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
24.07.2013, 14:26     реализация ThreadSafe функции #2
smithana, семафоры, мьютексы, евенты/таймеры (для извращенных личностей)
Или я не так вопрос понял?
smithana
2 / 2 / 0
Регистрация: 03.06.2009
Сообщений: 101
24.07.2013, 14:32  [ТС]     реализация ThreadSafe функции #3
Спасибо, правильно!
Но смысла менять данную конструкцию на семафоры и мьютексы - не вижу.
Нашёл CRITICAL_SECTION, но не могу понять для моей ли это ситуации.
CheshireCat
Эксперт С++
2907 / 1235 / 78
Регистрация: 27.05.2008
Сообщений: 3,307
24.07.2013, 15:14     реализация ThreadSafe функции #4
Проблемы ушли, говоришь? Хех. Есть мнение, что тебе просто везет. Пока :-)
smithana
2 / 2 / 0
Регистрация: 03.06.2009
Сообщений: 101
24.07.2013, 15:21  [ТС]     реализация ThreadSafe функции #5
Наверное не просто так я спрашиваю про корректность данного метода.
Если есть, что сказать по делу(сказать чем этот способ плох, предложить другой), я буду благодарен.
Если нет, то смысл злорадствовать?

з.ы.
Минус пока придумал только то, что если в функцию полезет одновременно больше двух потоков, будет хаос, и никакой очереди!
Praktolock
 Аватар для Praktolock
58 / 58 / 0
Регистрация: 29.11.2011
Сообщений: 272
24.07.2013, 15:30     реализация ThreadSafe функции #6
C++
1
2
while(entryCounter!= 0) Sleep(1);{
 entryCounter++;
Если поток прервётся между этих строк и начнёт работать другой, то твоя защита не сработает
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
24.07.2013, 15:32     реализация ThreadSafe функции #7
smithana, критические секции тоже подойдут.
Praktolock
 Аватар для Praktolock
58 / 58 / 0
Регистрация: 29.11.2011
Сообщений: 272
24.07.2013, 15:34     реализация ThreadSafe функции #8
Почему не сделать так:
C++
1
2
3
4
5
6
int some_function()
{
 EnterCriticalSection(&criticalsection);
 dosomeaction();
 LeaveCriticalSection();
}
?

Добавлено через 1 минуту
Да и дело не в том, что два потока выполняют одну и ту же функцию, а в том что они читают/пишут одни и те же данные.
CheshireCat
Эксперт С++
2907 / 1235 / 78
Регистрация: 27.05.2008
Сообщений: 3,307
24.07.2013, 15:36     реализация ThreadSafe функции #9
На самом деле, тебе уже nexen посоветовал - используй стандартные средства синхронизации, но не самописный код. А в твоем коде очень легко и непринужденно может возникнуть ситуация, когда в тело функции входят одновременно несколько потоков, и начинается хаос.

Критическая секция (если говорить о Win) - это именно то, что тебе нужно. Только не забудь обернуть ее объектом, реализующим идиому RAII, в противном случае огребешь проблем, если "вдруг" из середины функции вылетит исключение.
C++
1
2
3
4
5
6
int some_function() {
    EnterCriticalSection(&criticalsection);
    dosomeaction(); // <=== вот если здесь вылетит исключение, функция останется 
                    // заблокированной навсегда - дедлок. 
    LeaveCriticalSection(&criticalsection);
}
Ну или можешь использовать стандартные средства синхронизации - к чему душа больше лежит....
Praktolock
 Аватар для Praktolock
58 / 58 / 0
Регистрация: 29.11.2011
Сообщений: 272
24.07.2013, 15:38     реализация ThreadSafe функции #10
Цитата Сообщение от CheshireCat Посмотреть сообщение
если "вдруг" из середины функции вылетит исключение.
В обработчике исключений можно предусмотреть вызов LeaveCriticalSection(&criticalsection). Твой совет относится больше к обработке исключений впринципе, чем к многопоточнобезопасности.
CheshireCat
Эксперт С++
2907 / 1235 / 78
Регистрация: 27.05.2008
Сообщений: 3,307
24.07.2013, 15:44     реализация ThreadSafe функции #11
Ээээ, нет! А ты уверен, что любое исключение будет перехвачено? Ась? Исключения могут быть разными, и более того - если функция dosomeaction() вызывает другие функции, а те - еще третьи, и так далее, можно ли всегда уверенно сказать, какое исключение может вылететь из глубины сибирских руд? Не буду уж напоминать про C++-исключения и SEH-исключения....
Имхо лучше применить универсальный подход, гарантирующий отсутствие проблем при любых исключениях.
Praktolock
 Аватар для Praktolock
58 / 58 / 0
Регистрация: 29.11.2011
Сообщений: 272
24.07.2013, 15:46     реализация ThreadSafe функции #12
Если неизвестно какие исключения могут вылететь из
Цитата Сообщение от CheshireCat Посмотреть сообщение
из глубины сибирских руд
, то каким образом нам после этих самых исключений может понадобиться "дедлок" функция dosomeaction(), раз мы не собираемся обрабатывать исключения "из глубины сибирских руд" и наш шедевр завершится сообщив о необработанном исключении?
smithana
2 / 2 / 0
Регистрация: 03.06.2009
Сообщений: 101
24.07.2013, 15:52  [ТС]     реализация ThreadSafe функции #13
А есть ли смысл оборачивать в критическую секцию тело функции в самой функции в библиотеке?
Получается легче обернуть вызов функции библиотеки в самом многопоточном приложении.

идея была снять с разработчика приложения эту головную боль и реализовать threadSafe в самой библиотеке.
CheshireCat
Эксперт С++
2907 / 1235 / 78
Регистрация: 27.05.2008
Сообщений: 3,307
24.07.2013, 15:53     реализация ThreadSafe функции #14
Да лехко! Исключение может быть перехвачено и обработано в коде на несколько уровней выше по иерархии, чем функция dosomeaction(). Грубая схема:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
int f1()
{
    try {
        // некие действия....
        f2();
    }
    catch(...)
    {
        // тут как бы очистка....
    }
}
 
 
int f2()
{
    // тут еще куча кода...
    f3();
}
 
int f3()
{
    static CRITICAL_SECTION cs;
    // код инициализации опускаем...
    EnterCriticalSection(&cs);
    dosomeaction();
    LeaveCriticalSection(&cs);
}
 
void dosomeaction()
{
    // куча кода.....
    f4();
}
 
void f4()
{
    // куча кода....
    throw SomeEvil("Babah!");
}
Praktolock
 Аватар для Praktolock
58 / 58 / 0
Регистрация: 29.11.2011
Сообщений: 272
24.07.2013, 16:04     реализация ThreadSafe функции #15
Цитата Сообщение от smithana Посмотреть сообщение
А есть ли смысл оборачивать в критическую секцию тело функции в самой функции в библиотеке?
Зависит от твоей библиотеки. Ты хочешь упростить использование библиотеки потребителю? Решать тебе

Добавлено через 1 минуту
Цитата Сообщение от CheshireCat Посмотреть сообщение
Исключение может быть перехвачено и обработано в коде на несколько уровней выше по иерархии
Это называется плохо продуманная архитектура.

Добавлено через 7 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
int f1()
{
    try {
        // некие действия....
        f2();
    }
    catch(...)
    {
        // тут как бы очистка....
    }
}
 
 
int f2()
{
    // тут еще куча кода...
    f3();
}
 
int f3()
{
    static CRITICAL_SECTION cs;
    // код инициализации опускаем...
    EnterCriticalSection(&cs);
    try
    {
     dosomeaction();
    }
    catch(...)
    {
     LeaveCriticalSection(&cs);
     throw SomeEvil("Babah!");
    }
    LeaveCriticalSection(&cs);
}
 
void dosomeaction()
{
    // куча кода.....
    f4();
}
 
void f4()
{
    // куча кода....
    throw SomeEvil("Babah!");
}
Добавлено через 19 секунд
Раз уж очень приспичило можно и так
smithana
2 / 2 / 0
Регистрация: 03.06.2009
Сообщений: 101
24.07.2013, 16:10  [ТС]     реализация ThreadSafe функции #16
Спасибо большое, попробую перевести всё на критическую секцию.

Правильно ли я понимаю:
У каждой функции должна быть своя критическая секция (чтобы разные потоки могли вызывать разные функции одновременно).
Пример функции:
C++
1
2
3
4
5
6
7
8
bool lib_function{
  static CRITICAL_SECTION cs; 
  EnterCriticalSection(&cs);
  //тут тело самой функции где перед каждым возможным return false;
  //я ставлю LeaveCriticalSection(&cs);
  LeaveCriticalSection(&cs);
  return true;
}
Praktolock
 Аватар для Praktolock
58 / 58 / 0
Регистрация: 29.11.2011
Сообщений: 272
24.07.2013, 16:12     реализация ThreadSafe функции #17
Цитата Сообщение от smithana Посмотреть сообщение
Правильно ли я понимаю:
У каждой функции должна быть своя критическая секция
Нет, неправильно. Критичиские секции лучше ставить только при чтении/записи данных к которым может обратиться ещо что-то, для гарантии что эти данные во время чтения/записи не будут изменены чем-то еще. Иначе будет некислое падение производительности, если втыкать их везде где вздумается.
smithana
2 / 2 / 0
Регистрация: 03.06.2009
Сообщений: 101
24.07.2013, 16:30  [ТС]     реализация ThreadSafe функции #18
я опять не правильно выразился.
естественно не ко всем функциям библиотеки вообще, а только
к которым может обратиться ещо что-то
правильно ли я добавил вход и выход из критической секции?
CheshireCat
Эксперт С++
2907 / 1235 / 78
Регистрация: 27.05.2008
Сообщений: 3,307
24.07.2013, 16:38     реализация ThreadSafe функции #19
Да, вход и выход добавил правильно. Не забывай только про InitializeCriticalSection(&cs) и про возможные неприятности при исключениях. Удачи!
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
24.07.2013, 16:42     реализация ThreadSafe функции
Еще ссылки по теме:

Являются ли new / malloc threadsafe? C++
C++ Реализация функции strtok
C++ Реализация функции itoa

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Praktolock
 Аватар для Praktolock
58 / 58 / 0
Регистрация: 29.11.2011
Сообщений: 272
24.07.2013, 16:42     реализация ThreadSafe функции #20
Я чувствую, что ты упускаешь самый важный посыл в моих постах. Внимательно прочитай следующее. Не в коде дело, а в данных с которыми этот код работает, то есть например такая функция
C++
1
2
3
4
5
6
int veryimportantfuntcion(int a, int b)
{
 int c=a+b;      //неважно какой тут код,
 a=c*a*b;       //как мы видим он никаких данных кроме переменных
 return(a++);   //обьявленных внутри себя не меняет и не читает
};
Тут не нужно никаких критических секций, её могут хоть 100500 потоков одновременно запустить и ничего страшного не случится. Но если функция обращается к каким-либо данным из-вне, например так:
C++
1
2
3
4
5
6
void sortmassiv(int*massiv, int kolichestvoelementov)
{
 EnterCriticalSection(&cs);
 //тут сортируем массив
 LeaveCriticalSection(&cs);
};
То тут критическая секция нужна, ибо пока мы сортируем его, наш поток может быть прерван, и например длинна массива уменьшится, в то время как наша функция об этом не узнает, да и порядок нарушится и массив отсортируется неправильно

Добавлено через 4 минуты
Хочу посоветовать книгу Джеффри Рихтера "Создание эффективных win32-приложений с учетом специфики 64-разрядной версии windows". Там об этом есть
Yandex
Объявления
24.07.2013, 16:42     реализация ThreadSafe функции
Ответ Создать тему
Опции темы

Текущее время: 22:57. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru