Форум программистов, компьютерный форум, киберфорум
C/С++ под Linux
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.71/7: Рейтинг темы: голосов - 7, средняя оценка - 4.71
0 / 0 / 0
Регистрация: 30.05.2012
Сообщений: 8

Реализация собственного thread'a

30.05.2012, 16:16. Показов 1353. Ответов 9
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, задача следующая:
Нужно написать функцию int thread_create(void (*fp)()), которая реализует thread и в качестве стека для него использует локальный массив. В этом thread`e будет выполняться функция, на которую указывает fp, при чем thread получает управление сразу после создания.
Кроме того, надо написать функции void transfer_control_to_program, void transfer_control_to_thread, которые будут переключать управление между основной программой и реализованной нами нитью каждые 1/4 сек при помощи сигнала SIGALRM.

В общем-то сложность заключается именно с первой функции, а именно, как заставить программу воспринимать массив в качестве стека?
Я пытался с помощью inline assembly установить регистры ss на начало массива, а bp и sp на конец, но при запуске я получаю ошибку сегментирования. Есть идеи? буду очень благодарен
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
30.05.2012, 16:16
Ответы с готовыми решениями:

Реализация собственного события
Всем привет. Реализую собственное событие для компонента. И застрял с его условием вызова. Помогите кто знает.

Реализация собственного меню
Допустим, мы сделали меню где есть 3 кнопки. Допустим, первая - запуск, вторая - настройки, третья - выход. Как реализовывать переход к...

Реализация собственного умного укзателя
Доброго времени суток! При самостоятельной реализации умного указателя столкнулся с проблемой при удалении самого указателя. Код...

9
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
30.05.2012, 17:47
Цитата Сообщение от cstrike Посмотреть сообщение
В общем-то сложность заключается именно с первой функции, а именно, как заставить программу воспринимать массив в качестве стека?
Хорошего способа нет. Обычная практика setcontext/sigaltstack/модификация jmp_buf руками.
0
0 / 0 / 0
Регистрация: 30.05.2012
Сообщений: 8
30.05.2012, 19:12  [ТС]
Я не думаю, что там должно быть что-то сложное, так как решения всех задач нашего препода, как правило гениально просты, сложно только понять чего же он хочет.
Но и опцию с ручным изменением jmp_buf я тоже обдумывал, просто я понятия не имею какова его внутренняя структура и инфы на эту тему не нашел.
В любом случае, можно объяснение по поводу "setcontext/sigaltstack/"? То есть что это и как его понимать? (с linux имею дело впервые).
0
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
30.05.2012, 19:32
Цитата Сообщение от cstrike Посмотреть сообщение
Я не думаю, что там должно быть что-то сложное, так как решения всех задач нашего препода, как правило гениально просты, сложно только понять чего же он хочет.
Увы, простого (и более-менее аккуратного) решения тут не будет.
Цитата Сообщение от cstrike Посмотреть сообщение
Но и опцию с ручным изменением jmp_buf я тоже обдумывал, просто я понятия не имею какова его внутренняя структура и инфы на эту тему не нашел.
запустите grep jmp_buf /usr/include рано или поздно доберетесь до его структуры под нужную архитектуру.
Цитата Сообщение от cstrike Посмотреть сообщение
То есть что это и как его понимать?
прочитать эти man странички.
0
Заблокирован
30.05.2012, 23:52
Цитата Сообщение от cstrike Посмотреть сообщение
Нужно написать функцию int thread_create(void (*fp)()), которая реализует thread и в качестве стека для него использует локальный массив. В этом thread`e будет выполняться функция, на которую указывает fp, при чем thread получает управление сразу после создания.
Цитата Сообщение от cstrike Посмотреть сообщение
В общем-то сложность заключается именно с первой функции, а именно, как заставить программу воспринимать массив в качестве стека?
Цитата Сообщение от cstrike Посмотреть сообщение
Я не думаю, что там должно быть что-то сложное, так как решения всех задач нашего препода, как правило гениально просты, сложно только понять чего же он хочет.
верно думаете, thread_create в самом простом, как у вас, случае будет состоять из одной всего лишь строки, собственно из вызова clone. Ну и ему в качестве параметра там указатель на стек, который может быть массивом, полученным с помощью того же malloc


Цитата Сообщение от cstrike Посмотреть сообщение
Я пытался с помощью inline assembly установить регистры ss на начало массива, а bp и sp на конец
ss это 16битный регистр, содержащий индекс сегмента в GDT, в котором в свою очередь содержится база, лимит, уровень привелигий и прочее. Так что пихать в него указатель на массив бесмысленно. Ну и вобще об этом было догадаться просто потому, что он 2 байтный и адрес туда просто не влезет. Ну и кроме того, если попытаться записать чтото в ss будучи при этом не на нулевом кольце защиты, то процессор сгенерирует #GP и ядро пошлёт сигнал SIGSEGV процессу.

Вобщем пользуйтесь clone, он специально создан для реализации потоков
0
0 / 0 / 0
Регистрация: 30.05.2012
Сообщений: 8
31.05.2012, 15:54  [ТС]
Цитата Сообщение от g_u_e_s_t Посмотреть сообщение
запустите grep jmp_buf /usr/include рано или поздно доберетесь до его структуры под нужную архитектуру.
Подразумевается запустить эту команду в терминале из любой директории или из конкретной? У меня этот поиск не выдал никаких результатов.
Цитата Сообщение от g_u_e_s_t Посмотреть сообщение
прочитать эти man странички.
Прочитал, но не понял как пользоваться setcontext, буду благодарен если дадите пример. А насчет sigaltstack я так понял, что он устанавливает отдельный стек для обработчика сигналов (в моем случае это transfer_control_to_program, transfer_control_to_thread), а мне нужен отдельный стек для fp(). Поправте пожалуйста, если ошибаюсь.


Цитата Сообщение от LosAngeles Посмотреть сообщение
верно думаете, thread_create в самом простом, как у вас, случае будет состоять из одной всего лишь строки, собственно из вызова clone.
Опять же, если я не ошибаюсь, то thread это не отдельный, а все тот же процесс, как и создающий его (в отличие от fork()), а из man по clone() я понял, что будет создан совершенно новый процесс. Это не то что требуется.
0
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
01.06.2012, 09:15
Цитата Сообщение от cstrike Посмотреть сообщение
Подразумевается запустить эту команду в терминале из любой директории или из конкретной? У меня этот поиск не выдал никаких результатов.
Сочувствую. man grep про ключик -R
Цитата Сообщение от cstrike Посмотреть сообщение
Прочитал, но не понял как пользоваться setcontext, буду благодарен если дадите пример
C
1
2
ucontext_t context;
setcontext(&context);
Цитата Сообщение от cstrike Посмотреть сообщение
А насчет sigaltstack я так понял, что он устанавливает отдельный стек для обработчика сигналов (в моем случае это transfer_control_to_program, transfer_control_to_thread), а мне нужен отдельный стек для fp().
Смысл в том, что в обработчике сигнала можно сохранить контекст (3й параметр), а потом использовать его в своих целях. Техника обычно называется trampoline. На сколько я знаю большинство *nix реализаций userspace нитей/coroutines используют именно ее.
Цитата Сообщение от cstrike Посмотреть сообщение
Это не то что требуется.
clone() умеет и так и так. Вы уточните у преподавателя хочет ли он от Вас user space нитей/сопрограмм/фиберов или сгодятся и системные нити.
0
0 / 0 / 0
Регистрация: 30.05.2012
Сообщений: 8
10.06.2012, 21:28  [ТС]
Во-первых, извините за долгое отсутствие.
Во-вторых, всем спасибо за участие.
В-третьих, задача была благополучно решена следующим образом:

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
static sigjmp_buf jmpbp;
static sigjmp_buf jmpbt;
 
int thread_create(void (*fp)()){
    char arr[SSIZE];
 
    if(sigsetjmp(jmpbp, 1) == 0){
        ualarm(250000, 250000);
        if((signal(SIGALRM, transfer_control_to_program)) == SIG_ERR)
            printf("Signal error");
        fp();
    }
}
    
void transfer_control_to_thread(){
    if(sigsetjmp(jmpbp,1) == 0){
        if((signal(SIGALRM, transfer_control_to_program)) == SIG_ERR)
            printf("Signal error");
        siglongjmp(jmpbt,1);
    }
}
 
void transfer_control_to_program(){
    if(sigsetjmp(jmpbt,1) == 0){
        if((signal(SIGALRM, transfer_control_to_thread)) == SIG_ERR)
            printf("Signal error");
        siglongjmp(jmpbp,1);
    }
}
И у меня к вам назрел еще один вопрос: почему при отсутствии объявления char arr[SSIZE] в thread_create() происходит segmentation fault?
0
Заблокирован
11.06.2012, 01:15
Если вы хотите пользовательские потоки, то нужно было пользоваться ucontext, makecontext и swapcontext... Специально создано для этих целей. И если мне память не изменяет, то setjmp siglongjmp и прочее не обязаны сохранять состояние fpu. По крайней мере в Minix3 они этого не делают, а setcontext в конечном итоге приводит к вызову ядра sys_getmcontext, который сохраняет состояние fpu. То бишь если в ваших функциях вы будете работать с даблами, то всё это накроется медным тазом, а всё потому, что функции, которыми вы пользовались, вобщем то не предназначены для реализации многопоточности.

P.S.
Все библиотеки пользовательских потоков реализованы по одной схеме:
1) Вызывается инициализирующая функция. Она делает всякую фигню, например инициализирует шедулер, очередь потоков, которая может представлять из себя FIFO из структур thread_t, которая содержит ucontext и возвращает управление
2) Затем пользователь создаёт thread_creat поток. В libmtread в minix3 эта функция заполняет все поля в струтуре, описывающей поток, присваивает ему состоянии RUNNABLE и возвращает управление. В makecontext только не пользовательская функция передаётся, а mthread_trampoline
C
1
2
3
4
5
6
7
8
9
10
11
12
static void mthread_trampoline(void)
{
/* Execute the /current_thread's/ procedure. Store its result. */
 
  mthread_tcb_t *tcb;
  void *r;
 
  tcb = mthread_find_tcb(current_thread);
 
  r = (tcb->m_proc)(tcb->m_arg);
  mthread_exit(r);
}
это типа обёртка, mthread_exit вызывает mthread_schedule - сердце всей библиотеки, благодаря которому всё и работает. Там берётся поток в состоянии RUNNABLE из очереди и выполняется
Вот так приблизительно выглядит многопоточность, если вы не желаете использовать clone. А эти функции из вашего задания transfer_control_to_thread, transfer_control_to_program и постановка задачи непонятно какую смысловую нагрузку они несут и какую практическую ценность имеют. Я не представляю, для чего могут понадобится подобные функции и как их прикручивать в другие приложения, помоему никак... В каждой учебной задаче должна быть какая то мораль, как в басне. То есть выполняющий должен чтото усвоить, а что можно усвоить из этой задачи? Как не нужно писать чтоли?) Многопоточностью это назвать нельзя, это всё какой то большой бессмысленный костыль...


p.s. посмотреть реализацию libmthreads можно здесь http://code.metager.de/source/... ibmthread/ очень простая библиотека
p.p.s как запилить себе такую же штуку как по ссылке выше, то бишь крос референс, описано в моём скромном бложике здесь https://www.cyberforum.ru/blog... og442.html
0
0 / 0 / 0
Регистрация: 30.05.2012
Сообщений: 8
12.06.2012, 00:28  [ТС]
LosAngeles, спасибо за пояснения, было интересно узнать как это делается на проф уровне.
Но хочу заметить, что я не профессионал, я только учусь Смысловая нагрузка этого задания заключалось не в том чтобы разобраться в тонкостях нитей, а в том чтобы потренироваться использовать сигналы и глобальные переходы. И согласитесь, что делать такое задание (по крайней мере для новичка в этом деле) куда интереснее, чем реализация какого нибудь меню с возможность перехода откуда угодно в начало.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
12.06.2012, 00:28
Помогаю со студенческими работами здесь

Реализация собственного буфера обмена
Всем привет, пишу собственный буфер обмена, и возникло несколько вопросов: Во-первых: для работы необходима некая библиотека...

Реализация собственного события. QT4
Здравствуйте все! Пишу программу на QT4, где возникла необходимость, во всяком случае я так думаю, создать собственное событие. Мне нужно...

Реализация вызова собственного события
Добрый вечер. В данной теме https://www.cyberforum.ru/delphi-beginners/thread74814.html Mawrat доступно описал как создать свое событие и...

Реализация собственного класса вектора
Создать абстрактный тип данных - класс вектор, который имеет указатель на float, число элементов и переменную состояния. Определить...

Реализация собственного класса битовых массивов
Нужно на c# реализовать собственный класс для работы с битовыми массивами.должны быть хотя бы все 4 логические функции (not,and,or,xor). C...


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

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
Midnight Chicago Blues
kumehtar 24.03.2026
Такой Midnight Chicago Blues, знаешь?. . Когда вечерние улицы становятся ночными, а ты не можешь уснуть. Ты идёшь в любимый старый бар, и бармен наливает тебе виски. Ты смотришь на пролетающие. . .
Контроль уникальности заводского номера - вариант №2
Maks 24.03.2026
В отличие от предыдущего варианта добавлено прерывание циклов, также добавлены новые переменные для сохранения контекста ошибки перед прерыванием цикла: Процедура ПередЗаписью(Отказ, РежимЗаписи,. . .
SDL3 для Desktop (MinGW): Вывод текста со шрифтом TTF с помощью библиотеки SDL3_ttf на Си и C++
8Observer8 24.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-text-sdl3-c. zip finish-text-sdl3-cpp. zip
Жизнь в неопределённости
kumehtar 23.03.2026
Жизнь — это постоянное существование в неопределённости. Например, даже если у тебя есть список дел, невозможно дойти до точки, где всё окончательно завершено и больше ничего не осталось. В принципе,. . .
Модель здравоСохранения: работники работают быстрее после её введения.
anaschu 23.03.2026
geJalZw1fLo Корпорация до введения программа здравоохранения имела много невыполненных работниками заданий, после введения программы количество заданий выросло. Но на выплатах по больничным это. . .
Контроль уникальности заводского номера - вариант №1
Maks 23.03.2026
Алгоритм контроля уникальности заводского (или серийного) номера на примере документа выдачи шин для спецтехники с табличной частью. Данные берутся из регистра сведений, по которому настроено. . .
Хочу заставить корпорации вкладываться в здоровье сотрудников: делаю мат модель здравосохранения
anaschu 22.03.2026
e7EYtONaj8Y Z4Tv2zpXVVo https:/ / github. com/ shumilovas/ med2. git
Программный отбор элементов справочника по группе
Maks 22.03.2026
Установка программного отбора элементов справочника "Номенклатура" из модуля формы документа. В качестве фильтра для отбора справочника служит группа номенклатуры. Отбор по наименованию группы. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru