Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Вопрос по многопоточности  (Прочитано 22617 раз)
0 Пользователей и 1 Гость смотрят эту тему.
AlexCasual
Помогающий

by
Offline Offline

« : 14-07-2011 20:30 » 

Имеется цикл в котором создаются потоки с одинаковой потоковой функцией find_in_path() :

hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)find_in_path,NULL,0,NULL);

Если я правильно понимаю,то все переменные,определённые внутри find_in_path(),будут локальными для каждого из создаваемых потоков и доступ к ним синхронизировать не нужно? - Но при таком ходе мысли у меня нарушается логика работы функции find_in_path() в каждом из потоков (попрасту говоря - неверно работает)...Если же код внутри find_in_path() обернуть в критическую секцию,то всё работает верно...
Или я чего-то не понимаю?
Записан
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 14-07-2011 20:40 » 

Есть нюансы.

Во-первых, если есть статические переменные в функции find_in_path, то будет существовать только один экземпляр такой переменной (возможно, даже будет неопределённое поведение), поскольку такие переменные создаются в момент первого вызова функции.

Во-вторых, использование функций из Runtime-библиотеки (CRT) может окончиться плохо в многопоточной среде, потому что они используют глобальные переменные. Чтобы таких проблем не было, нужно использовать _beginthread/_beginthreadex вместо CreateThread.
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #2 : 15-07-2011 04:04 » 

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

Хотелось бы посмотреть на код find_in_path, не видя кода можно строить сколь угодно хитрые теории, которые никак не связаны с жизью
Записан

Странно всё это....
AlexCasual
Помогающий

by
Offline Offline

« Ответ #3 : 15-07-2011 16:27 » 

В функции find_in_path() я использую связку FindFirstFile()/FindNextFile() - может ли это быть причиной глюкавости работы?

А хотя вот и код :

Код: (C++)
bool find_in_path(const char *_path)
{
        WIN32_FIND_DATA ffd;
        HANDLE hFind;

        std::string path = _path;
        std::string thread_path = _path;

        path.append("\\*.*");

         printf("%s %s \n","THREAD***",path.c_str());
         printf("%s %d \n","ID",GetCurrentThreadId());

        hFind = FindFirstFile(path.c_str(),&ffd);

        while(FindNextFile(hFind,&ffd) != 0)
        {                      
                if(strcmp(ffd.cFileName,"..") != 0)
                {
                        if(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                    {
                                        thread_path = path;
                                        thread_path.resize(thread_path.size() - 3);
                                        thread_path.append("\\");
                                        thread_path.append(ffd.cFileName);

                                        //find_in_path(thread_path.c_str());
                                        start_thread(thread_path.c_str());
                                }
                                else
                                {    printf("%s \n","FILE***");
                                         printf("%s \n",ffd.cFileName);
                                }
                                     
                        }
                }
 
 FindClose(hFind);

        return true;
}
« Последнее редактирование: 15-07-2011 22:50 от RXL » Записан
Ochkarik
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 15-07-2011 22:07 » 

std::string  не очень потокобезопасна, насколько я слышал.... проверьте)

PS start_thread(thread_path.c_str()); - это шо?
« Последнее редактирование: 15-07-2011 22:21 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
AlexCasual
Помогающий

by
Offline Offline

« Ответ #5 : 16-07-2011 08:57 » 

Код:
bool start_thread(const char *_path)
{
HANDLE hThread;

              EnterCriticalSection(&cs);
memcpy(str,_path,256);
LeaveCriticalSection(&cs);

hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)find_in_path,str,0,NULL);

thread_handles.push_back(hThread);
return true;
}
« Последнее редактирование: 16-07-2011 08:59 от AlexCasual » Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #6 : 16-07-2011 17:29 » 

std::string  не очень потокобезопасна, насколько я слышал.... проверьте)


оно тут не причём, переменная локальная и не шарится потоками

AlexCasual,
Код:
        EnterCriticalSection(&cs);
memcpy(str,_path,256);
        LeaveCriticalSection(&cs);

что такое str и и почему оно в критической секции?
дай угадаю, глобальная переменная, которая вроде как защинена? но она ничем не защищена на самом, то деле
ты её еще не успел передать в поток, а оно уже поменялось другим потоком
memcpy в состоянии вызвать ошибку доступа к памяти, т.к. оно не проверяет размер входного буфера
Код: (C++)
strncpy(str,_path,256);
str[sizeof(str) - 1 ] = 0;
Записан

Странно всё это....
Ochkarik
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 16-07-2011 20:51 » 

Антон (LogRus), могло бы быть "при чем", я ж кода start_thread не видел куда буфер уплывает Да-да
просто такую фразу нашел...
...но поскольку специалистом по С++ не являюсь, интересно услышать ваше мнение
Цитата
Рассмотрим пример:

std::string   a = "abc";
std::string b = a;
Для многих реализаций обе переменные a и b будут указывать на один и тот же буфер в памяти, по-возможности, отслеживая моменты, когда необходимо "расщепить" общий буфер, дав каждой переменной по своей копии.

Однако в случае многонитевых приложений подобная политика запросто приводит к возникновению т.н. raise condition, например, одна нить может уничтожить одну переменную, а другая - что-то записать в нее. При этом сущесвтует вероятность того, что произойдет обращение к уже освобожденному блоку памяти и падению программы.
- стринги действительно могут ТАК выделять память?
источник
 

PS str[sizeof(str) - 1 ] = 0;
- не только. ошибка еще и в том, что размер _path - может быть меньше 256. тогда выход за границы при копировании.
в случае если размер больше... ошибка по отсутствию нуля в конце, либо выход за границы но уже в новой нити, при инициализации стрингов.
PPS размер пути в NTFS может достигать 32к символов юникода, каждая компонента - до 256 символов.
« Последнее редактирование: 16-07-2011 21:08 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #8 : 18-07-2011 05:19 » 

Ochkarik, уг Улыбаюсь
что касается цитаты, то я не видел ни разу такой реализации (глядел на STLport, gcc и в STL от MS не припомню такого), а пукт "21.4.2   basic_string constructors and assigment operators" утвержадет, что конструктор создаёт копию.

В любом случае я думаю писатели библиотек учли бы особенность нитей при реализации CopyOnWrite для строк, иначе имхо поведение слишком не детерминированно, что бы ей пользоваться

про PS: поэтому там строчкой выше копирование через strncpy
Записан

Странно всё это....
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 18-07-2011 08:05 » 

Я бы, в любом случае, запускал поток через _beginthread/_beginthreadex - строка, может, и не при чём, но CRT там в хвост и в гриву используется - где-нибудь что-нибудь да всплывёт. Тот же printf наверняка использует какой-нибудь не-потокобезопасный буфер.

Кстати, от printf, вызываемого из многих потоков разом, я бы и не ожидал корректной работы. Если этот вывод нужен - лучше его как-то изолировать.
Записан
Ochkarik
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 18-07-2011 10:24 » new

Антон (LogRus), да, пардон, слона то я и не заметил)
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines