C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Многопоточность, вызов одной и той же подпрограммы
Grigoriy
Отправлено: 26.05.2006, 12:19


Мастер участка

Группа: Участник
Сообщений: 381



Вопрос по многопоточности, уважаемые форумчане.

В рамках одного приложения имеются два или несколько потоков команд.
Имеется также некоторая подпрограмма A, которую могут вызвать все эти потоки.
Подпрограмма использует локальные переменные.
Все потоки запущены. В каждом из них встречается инструкция процессора для вызова подпрограммы A.

Вопрос заключается в том, как вызовы одной и той же подпрограммы согласуются между собой ?
Может произойти ситуация когда подпрограмма A будет выполнятся многопоточно. Тогда в рамках каждого потока должна существовать собственная область памяти в стеке для локальных переменных. Тут возникает подвопрос.
А не разные ли сегменты стека выделяются для разных потоков ?
Ведь если сегмент стека общий, то может возникнуть конфликт все равно ! Например, один поток записывает в стек что-то, другой — читает.
Doga
Отправлено: 26.05.2006, 14:18


Мастер участка

Группа: Участник
Сообщений: 575



TThread::Synchronize, TCriticalSection
olegenty
Отправлено: 26.05.2006, 15:12


Ветеран

Группа: Модератор
Сообщений: 2412



вызывай где и как угодно, в случае использования только локальных переменных никакого криминала не возникнет.
Grigoriy
Отправлено: 26.05.2006, 16:24


Мастер участка

Группа: Участник
Сообщений: 381



QUOTE (olegenty @ 26/05/2006, 15:12)
вызывай где и как угодно, в случае использования только локальных переменных никакого криминала не возникнет.

Да про глобальные переменные понятно.

Но, все таки интересно, у разных потоков разные сегменты стека ? cool.gif cool.gif
Grigoriy
Отправлено: 26.05.2006, 20:18


Мастер участка

Группа: Участник
Сообщений: 381



Хорошо.
Я расскажу по подробнее.
Я составляю набор функций для работы с так называемыми файлами
"*.MMP", которые хранят текстуры (в каждом файле может хранится несколько текстур).
И там есть 3 формата кодирования изображений — 8-битный, 24-битный, 32-битный (с alpha-каналом).
Я добился хорошего качества кодирования в формат 8-бит/пиксел из формата 24 бит/пиксел и при чем за небольшое время идет кодирование.

Потом все эти файлы нужно объединить в DLL-библиотеку. Но составлять я её буду на АСМе FASM.

Эту библиотеку будет использовать менеджер MMP-текстур, с помощью которого можно будет работать с файлами текстур как с архивами.

Я уже составил несколько программ разных версий для компиляции MMP-файлов, но недостаток у них в том, что в процессе кодирования текстур все время обрабатывается событие нажатия на кнопку и эта обработка и есть кодирование и сохранение MMP-файла. Окно в это время не обновляется и его нельзя перетащить в другое место. Вообще нельзя больше ничего делать в этой программе. Мне нужно сделать так, чтобы можно было кодировать в фоновом режиме. Для этого нужно создать отдельный поток команд. Но я пока не знаю как лучше это сделать. И вот возник вопрос.
Если допустим начался один фоновый процесс кодирования нескольких файлов изображений в один MMP-файл текстур, и пользователь запускает второй фоновый процесс кодирования. Они эти оба фоновых процесса выполняются параллельно.
Будет возникать ситуация, когда одна и та же подпрограмма выполняется многопоточно.
И тут правильно подметил olegenty, что глобальные переменные нельзя в таком случае использовать в таких подпрограммах.
Дело усложняется тем что я использую много глобальных переменных сейчас в своем наборе подпрограмм, нужно от глобальных ячеек памяти избавляться. Использование глобальных переменных вместо локальных вынужденно тем, что при вызове подпрограмм библиотеки gdiplus.dll непосредственно на ассемблере не работают ссылки на локальные переменные. Просто четырехбайтный указатель, который записывается в стек перед вызовом системной функции не может ссылаться на ячейку в сегменте стека — это проверено уже. По видимому различные базовые адреса у стека и у сегмента данных. Ну в общем указатели на локальные переменные при вызове системных функций не работают.
Тут есть ещё один метод решения этой проблемы.
Использовать локальные переменные-указатели. При работе подпрограммы будет выделятся память с помощью системной функции GlobalAlloc. Например так
CODE

void* p;
//------------------------
push 10000000;
push 0;
call GlobalAlloc;
mov p, eax;
/*после этого указатель p указывает на неперемещаемый блок памяти размером 10 МБ*/
//---------------
//освобождаем память
push p;
call GlobalFree;


Таким образом я полностью избавлюсь от влияния многопоточной работы одной и той же области кода на глобальные переменные.

Но мне нужно окончательно убедится в том, что все будет работать четко без глюков.
Мне нужно понять почему в таком случае нет конфликта между потоками через стек. У каждого из них собственный сегмент стека, что ли ?
Grigoriy
Отправлено: 27.05.2006, 16:42


Мастер участка

Группа: Участник
Сообщений: 381



QUOTE
Использование глобальных переменных вместо локальных вынужденно тем, что при вызове подпрограмм библиотеки gdiplus.dll непосредственно на ассемблере не работают ссылки на локальные переменные. Просто четырехбайтный указатель, который записывается в стек перед вызовом системной функции не может ссылаться на ячейку в сегменте стека — это проверено уже. По видимому различные базовые адреса у стека и у сегмента данных. Ну в общем указатели на локальные переменные при вызове системных функций не работают.


Теперь я понял свою ошибку.
Просто заранее неизвестно смещение в стеке для локальной переменной. И в случае
CODE

int proc1(int d, int r)
{
int a,b;
//-------------
asm{
push offset a;};
};

команда push не будет записывать смещение локальной переменной a относительно стека, а будет записывать смещение этой переменной относительно текущего блока локальных переменных функции. Для коррекции нужно применить команду
CODE

//-------
push offset a;add [esp],ebp;
//-------


Применил эту коррекцию — все работает нормально.

Вернуться в Вопросы программирования в C++Builder