Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Программирование под Unix/Linux > Передача управления следующему потоку FreeBSD


Автор: Wolf 28.8.2010, 15:02
Доброго времени суток! Каким образом во FreeBSD управление можно передать другому (следующиму) потоку?

Вот скажем есть у меня бесконечный цикл:

Код

while (true) {
     ...
    
     //Вот тут требуется вставить вункцию, которая
     //дала операционной системе понять, что
     //нужно обслуживать следующий поток, а
     //этот подождёт.
}

Автор: boostcoder 28.8.2010, 16:04
Цитата(Wolf @  28.8.2010,  15:02 Найти цитируемый пост)
передать другому (следующиму) потоку?

не уверен что правильно понял вас...

вам нужно выполнение какой-то функции распределять между потоками?

если да, то так:
Код

#include <iostream>
#include <boost/thread.hpp>

void somefunction(int arg) {
   std::cout << "somefunction(" << arg << ")" << std::endl;
}

int main() {
   const size_t cores = 4;
   boost::thread_group threads;
   
   for ( size_t idx = 0; idx < cores; ++idx ) {
      threads.create_thread(boost::bind(somefunction, rand()));
   }
   
   threads.join_all();
   
   return 0;
}

это простой вариант. в нем возможно создание слишком многого кол-ва потоков. за этим нужно следить самому.
суть в том, что просто создаются потоки, кол-во которых, можете задавать произвольно. шедулер ОС сам распределит их.
потоки сами будут удаляться тогда, когда вернется управление из somefunction().

правильный вариант - использовать boost::asio::io_service в связке с boost::thread_group.

Автор: MAKCim 28.8.2010, 16:34
Wolf
sched_yield

Добавлено через 1 минуту и 25 секунд
boostcoder
я вообще не понимаю, зачем приводить такие примеры?

Автор: boostcoder 28.8.2010, 16:39
Цитата(MAKCim @  28.8.2010,  16:34 Найти цитируемый пост)
такие

какие?

Автор: MAKCim 28.8.2010, 23:05
boostcoder
у автора даже намека нет на использование boost'а
это раз (да и вообще, в этом разделе форума советовать boost как-то не кошерно, имхо)
во-вторых, если не поняли вопрос, уточните
смысл телепатии с не имеющим отношения к сути вопроса кодом?

Автор: boostcoder 28.8.2010, 23:15
Цитата(MAKCim @  28.8.2010,  23:05 Найти цитируемый пост)
у автора даже намека нет на использование boost'а

а это что ,что-то из ряда вон выходящее?

Цитата(MAKCim @  28.8.2010,  23:05 Найти цитируемый пост)
во-вторых, если не поняли вопрос, уточните

я и предположил, что возможно не верно понял задачу..
Цитата(boostcoder @  28.8.2010,  16:04 Найти цитируемый пост)
не уверен что правильно понял вас...



Цитата(MAKCim @  28.8.2010,  23:05 Найти цитируемый пост)
смысл телепатии с не имеющим отношения к сути вопроса кодом?

как минимум, никому от этого не хуже.

Автор: MAKCim 29.8.2010, 10:48
boostcoder
Нет, это не что-то из ряда вон выходящее
просто boost это не та либа, которую в принципе можно сувать (ака предлагать) куда/где попало: есть куча всяких задач, начиная с использования только С и заканчивая специфическими окружениями, где boost не применим

Короче, считаю пример бессмысленным в плане пользы автору от него...проехали в общем

Автор: Wolf 29.8.2010, 12:33
Пример номер два. С ним, я думаю, будет яснее.

Код

#include <iostream>

using namespace std;

int main()
{
    int i = 0;

    while (true) {
        i++;
    }

    return 0;
}


В любой операционной системе данный код приведёт к 100% загрузке процессора (или ядра на котором код выполняется) (пример - прикреплённый рисунок). Мне нужно избавиться от 100% загрузки процессора. И так, что можно для этого вставить в цикл while (true) {} ?

Автор: MAKCim 29.8.2010, 13:08
я же сказал, sched_yield
Код

#include <iostream>
using namespace std;
int main()
{
    int i = 0;
    while (true) {
        i++;
       sched_yield();
    }
    return 0;
}

Автор: Wolf 29.8.2010, 13:13
MAKCim, большое спасибо! Не заметил сразу.

Автор: Wolf 31.8.2010, 05:44
Что-то это не помогает. В top смотрю, разница лишь в том, что с sched_yield система грузит проц под 100%, а без sched_yield, приложение. А как можно на очень короткое время переводить процесс или поток в ожидание?

Автор: REZiaMIX 31.8.2010, 08:53
Цитата(Wolf @ 31.8.2010,  05:44)
Что-то это не помогает. В top смотрю, разница лишь в том, что с sched_yield система грузит проц под 100%, а без sched_yield, приложение. А как можно на очень короткое время переводить процесс или поток в ожидание?

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

Автор: MAKCim 31.8.2010, 10:18
Wolf
это поможет если большинство процессов не ограничены вводом-выводом
в противном случае просто некому грубо говоря передать управление и оно переходит обратно к вызывающему потоку

Автор: Wolf 1.9.2010, 15:02
У меня не while(true), а примерно такое в потоках, занимающихся IO сокета:

Код

bool TermFlag;

//это функция потока
void *ThreadProc(void *Param)
{
     while (!TermFlag) {
          //Здесь распологаются функции обработки сокетов
          //как по другому, если не циклом, опрашивать их
          //состояние?
     }

     TermFlag = false;
}

//эта функция вызывается из управляющего потока
//для завершения потока
void Terminate()
{
     TermFlag = true;

     //Ждём окончания цикла функции потока
     while (TermFlag) ;
}


Скорее всего я не правильно понимаю работу планировщика. В общем если в цикле ваил тру есть, что считать, например i++, и процессор свободен, то вот, собственно говоря он и считает на 100% ресурса процессора. Как то так, видимо.

Автор: djamshud 1.9.2010, 15:04
Wolf, man select, man epoll, man poll.

Автор: Wolf 1.9.2010, 15:37
djamshud, это то тут причём? Разумеется этим мультиплексируется обработка клиентов.

Вопрос в другом. Прочтите 1 пост.

Автор: djamshud 1.9.2010, 15:39
Wolf,

Цитата

          //Здесь распологаются функции обработки сокетов
          //как по другому, если не циклом, опрашивать их
          //состояние?


Загнать их в селект?

Автор: Wolf 1.9.2010, 15:44
djamshud, они и так группами опрашиваются этими функциями. Но эти функции с определённой переодичностью нужно вызывать. Вызываются они в цикле потоков (грубо говоря всё, конечно).

Автор: djamshud 1.9.2010, 15:51
Wolf, извините, если я что-то не понимаю, но...

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

Добавлено через 57 секунд
Собственно, даже если состояние их не изменилось, управление вернется через указанный таймаут.

Автор: Wolf 2.9.2010, 06:49
djamshud, Вы не понимаете, что речь не о сокетах и методах мультиплексирования.

Ну и чтобы вам было яснее. Клиентов более 2000. Потоков в зависимости от настройки от 1 до какого либо разумного предела (пул потоков). Потоки тормозить нельзя (тем же самым блокирующим режимом select). По этому таймаут 0. Что можно читать - читаем, что можно отослать - отсылаем (опять же чётко и без блокировок). Далее берём новую группу сокетов и обрабатываем. Непрерывно.

Автор: MAKCim 2.9.2010, 08:48
Wolf
ну а то, что вы хотите, это ведь тоже своего рода блокирование
если поток не занимается ничем иным кроме работы с сокетами, то действительно непонятно, зачем непрерывный опрос

Добавлено через 2 минуты и 17 секунд
ну и по архитектуре
у каждого потока должно быть свое множество сокетов, с которым он может работать неконкурентно с другими потоками

Автор: Wolf 2.9.2010, 15:20
MAKCim, пока что архитектура такова, что действительно существует конкуренция. Общий список клиентов к нему обращаются потоки для получения группы сокетов. Сокеты не закреплены за какими либо потоками. И скорее всего действительно придётся переписать механизм обработки сокетов. Вы меня заставили задуматься. Мои радужные представления о текущей архитектуре могут рухнуть  smile 

А что посоветуете? По идее должен быть нагруженный сервер с множеством клиентов. Клиенты обмениваются между собой данными и между базами сервера. Скажем сервер видео конференций + сервер какого либо контента.

Автор: MAKCim 2.9.2010, 21:56
какой бы не был нагруженный сервер, всегда существует лимит одновременно обрабатываемых соединений
обусловленный производительностью системы и толщиной канала
обозначим лимит через L, а число ядер/процессоров - через N
каждому ядру/процессору соответствует поток/процесс
максимальное число соединений для него L/N
итого имеем матрицу размером L*N
каждый элемент - дескриптор (указатель, структура, ...) соединения
есть один поток, постоянно вызывающий accept()
полученный сокет диспетчеризируется одному из N потоков/процессов
каждый из N потоков/процессов циклично выполняет 3 действия
1) опрос новых соединений и добавление их в select/poll/epoll/kqueue/...
2) мультиплексирование
3) обработка
в 1) нет блокировки, т. к. у каждого потока/процесса своя часть матрицы, а доступность
нового соединения определяется флагом дескриптора
чтение и установка флага могут осуществляться параллельно без лока

Автор: Wolf 3.9.2010, 07:59
MAKCim, а что насчёт общих данных и обмена сообщениями между клиентов? Тут то тоже блокировка.

Автор: MAKCim 3.9.2010, 09:14
Wolf
добавить в каждый дескриптор очередь
сообщение кидаем в очередь
соответственно добавляем пункт 4) - проверка очереди на предмет новых сообщений
очередь защищается спин-локом
чтение очереди у меня всегда выглядит след. образом
Код

lock(l);
list_replace_init(queue, temp);
unlock(l);
// обрабатываем temp без лока

list_replace_init имеет сложность O(1)

Автор: Wolf 3.9.2010, 11:47
MAKCim, тут опять же возникает множество вопросов. Как поток которому нужно передать от клиента А клиенту Б сообщение узнает в каком потоке находится его клиент? Если не будет общего списка. Второй вопрос, кто удаляет клиентов из списка? Логично, что  поток, обрабатывающий клиента. Но удалив его дескриптор, может возникнуть такая ситуация, когда кто-то пытается в удалённый из памяти дескриптор (и, соответственно, его очередь) добавить сообщение.

Извеняюсь, что уже оффтопик пошёл. Можно создать или обсудить в другой теме.

Автор: MAKCim 3.9.2010, 16:26
Цитата(Wolf @  3.9.2010,  11:47 Найти цитируемый пост)
Как поток которому нужно передать от клиента А клиенту Б сообщение узнает в каком потоке находится его клиент?

просто ;)

поток, дергающий accept(), поддерживает map адресов клиентов и перед диспетчеризацией соединения одному из потоков добавляет {ip, id} в map
ip - адрес клиента
id - номер потока
соответственно, каждый из потоков, например через пайп, связан с ним
все пайпы мультиплексируются им равно как и listen-сокет

когда i-ый поток хочет получить номер потока, он пишет в пайп запрос и получает результат

в принципе эта же схема работает и для взаимодействия между потоками (вместо очередей)
но скорость может быть ниже
Цитата(Wolf @  3.9.2010,  11:47 Найти цитируемый пост)
Второй вопрос, кто удаляет клиентов из списка? Логично, что  поток, обрабатывающий клиента. Но удалив его дескриптор, может возникнуть такая ситуация, когда кто-то пытается в удалённый из памяти дескриптор (и, соответственно, его очередь) добавить сообщение.

матрица _не удаляется_, она статична
когда, соединение закрывается, поток достает его из select/poll/epoll/kqueue..., освобождает ресурсы и устанавливает флаг FREE в дескрипторе

когда аккептор ищет свободный дескриптор для диспетчеризации, он освобождает очередь запросов (т. к. клиент уже давно мертв)

Автор: Wolf 11.9.2010, 09:21
MAKCim, спасибо, теперь многие моменты прояснились smile А что можно почитать по сетевой архитектуре?

Автор: MAKCim 11.9.2010, 10:02
Wolf
боюсь только практика ну и плюс примеры реальных приложений
в книгах описание подобного рода вещей я как-то не встречал
но Стивенс в любом случае не повредит ;)

Автор: Wolf 11.9.2010, 13:31
MAKCim, да я вот тоже понимаю, что лучше всего было бы работать по этому направлению в организации какой нибудь, и лучше не какой нибуть. К сожалению на данный момент нет такой возможности. У нас в городе это не востребовано. Нужно переезжать smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)