реклама на сайте
подробности

 
 
> Управление контекстом БЕЗ RTOS
yanvasiij
сообщение Nov 21 2014, 08:04
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 321
Регистрация: 23-12-11
Из: Уфа
Пользователь №: 69 041



Я понимаю, что сейчас речь пойдет об изобретении велосипеда. Но мне это важно для понимания. В ОСРВах переключение между задачами осуществляется за счет переключения контекста. Мне интересно каким образом можно организовать такое переключения самостоятельно. Например, есть две функции ledBlinking1() и ledBlinking2():
Код
void ledBlinging1 (vodi)
{
    led1On();
    delayms(1000);
    led1Off();
    delayms(1000);
}

void ledBlinging2 (vodi)
{
    led2On();
    delayms(1000);
    led2Off();
    delayms(1000);
}

При размещении этих функций внутри задач rtos они будут моргать не влияя друг на друга. А если я озадачусь сделать тоже моргание без rtos, так чтобы они моргали независимо, то мне придется накидать витиеватый алгоритм запоминания предыдущего состояния и следить, сколько времени прошло, не пора бы потушить или зажечь... Но если я реализую функцию загрузки и выгрузки контекста функции, то такой алгоритм городить не придется. Пусть такая функция есть и называется она downloadContext (), а функция приостановки и сохранения контекста yeld(). Тогда, то же моргание без РТОС будет выглядеть следующим образом:

Код
void ledBlinging1 (void)
{
    led1On();
    timer1.setMs(1000);
    while (timer1.expired() == FALSE) yeld();
    led1Off();
    timer1.setMs(1000);
    while (timer1.expired() == FALSE) yeld();

}

void ledBlinging2 (void)
{
    led1On();
    timer1.setMs(1000);
    while (timer2.expired() == FALSE) yeld();
    led2Off();
    timer2.setMs(1000);
    while (timer2.expired() == FALSE) yeld();
}

int main (void)
{
    while (1)
    {
        downloadContext (ledBlinging1);
        downloadContext (ledBlinging2);
    }
}


Может я чего неправильно сказал, но надеюсь смысл понятен. Вопрос: как сделать такое сохранение и загрузку контекста? Где про это можно почитать, посмотреть пример и т.п.
Спасибо!
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
WitFed
сообщение Nov 27 2014, 14:04
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 271
Регистрация: 6-12-11
Из: Taganrog
Пользователь №: 68 701



Я лично после долгого знакомства с ОС2000 без отладчика и попытками обуздать там 100 нитей очень негативно отношусь ко всякой шизофрении, когда непонятно, "кто шил костюм", а память портится, причём нестабильно.
Хотя периодически сильно хочется почитать научный обзор страниц так на 100, что же там придумано на текущий момент в этой области. Но по-русски и без наездов.
Лучше всего ИМХО 1-нитевые "шедулеры", которые по очереди исполняют функции, которые были добавлены в список до того, и каждая функция добавляет новые адреса исполнения в список, плюс её возвращаемое значение -- адрес функции, которая должна выполниться после этой, ну или 0, если эта "нитка" завершена.
Задача бъётся на кучу функций, которые имеют глобальные данные (возможно, в отдельных namespace, или там там сидят указатели на них в куче), и никакого сохранения контекста и переключения десятков регистров не нужно, стек у всех один ! Бродить в переключателе контекста на asm-е не надо, чтобы понять, куда меня перешедуливают, само переключение -- выход из одной функции и вызов другой, данные глобальны.
Шедулер тупо вызывает по кругу свой массив адресов функций, они "как бы крутятся", возвращая вместо себя "наследника" в тот же адрес массива на то же место, и что-то кусочно исполняют.
Также можно завести отдельный массив "ожидателей" -- системного таймера или не 0 по какому-то адресу, который будет и "семафором", "мьютексом", и чем угодно -- не нужны никакие критические секции, никто у тебя за спиной бяку никогда не сделает в непонятной нити с высоким приоритетом, лишь бы был отладчик хоть какой-то в IDE.
Прерывания тоже можно использовать, но только в виде исключения -- если уж точно кто-то чего-то требует за 100 тактов, а не за 1000 (в порядке очереди). Ибо от прерываний основные проблемы нестабильности в ртосах всяких, когда и надо что-то бы сделать "где-то", а "там" в этот же момент тоже вдруг кто-то ковыряется "под стрелой"...
Такие коды получаются абсолютно переносимыми (ну, кроме таймера), без-ассемблерными. И все контексты сидят "в домиках" возле каждой функции, их использующей, локальные автоматические переменные действуют недолго и не требуют сохранения между вызовами. Понятно, что ожидания и большие объёмы обработки там недопустимы, надо бить процессы на непрерывные куски.
Случилось нечто -- запускается "процесс" его обработки, т.е. подшедуливается функция, где она расписана.
Единственное плохо -- все варианты событий должны быть известны заранее, хотя во встроенных небольших системах так обычно и есть. Можно и параметры передавать в шедулер, с которыми планируется вызов функции, но это уже непрозрачней гораздо.
Код ТС получается типа такого:
Код
typedef (func*)(void);
func led1On() {/*make*/ addDelayed(led1Off, 1000); return NULL; }
func led1Off() {/*make*/ addDelayed(led1On, 1000); return NULL; }
func led2On() {/*make*/ addDelayed(led2Off, 1000); return NULL; }
func led2Off() {/*make*/ addDelayed(led2On, 1000); return NULL; }

int main() {
  addDelayed(led1On, 1000);
  addDelayed(led1Off, 1000);
  main_loop();
}

Вдруг на самом деле что такое уже есть в мировой практике -- подскажите.
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 28 2014, 07:04
Сообщение #3


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(WitFed @ Nov 27 2014, 16:04) *
Лучше всего ИМХО 1-нитевые "шедулеры", которые по очереди исполняют функции, которые были добавлены в список до того, и каждая функция добавляет новые адреса исполнения в список, плюс её возвращаемое значение ...


Извините, но ваш пост воспринимается как малопонятный набор слов.
А приведенный код попахивает рекурсией. А рекурсия это самое вредное что можно придумать во встраиваемой системе. Убьете стек и не заметите.

Может вы хотели сказать о машинах состояний управляемых шаблонами (цепочками состояний)?
На более высоком уровне это называется интерперетаторы.

Приведу пример простейшей машины состояний по шаблону отрабатывающей управление массивом соленоидов.

Соленоиды в автоматике довольно хитро управляются.
Во первых их нельзя включать одновременно, во вторых их модулируют ШИМ-ом, в третьих к ним применяют специальные форсированные импульсы, но так чтобы не перегреть.
Вообщем требуют таких же сложных шаблонов как и информационные светодиоды.

Этот автомат применяется мною и с RTOS и без.
Сервисы RTOS здесь мало применимы, потому что им тут нечего делать и поскольку момент коммутации соленоидов строго привязан к окончанию выборки АЦП, так чтобы они не засоряли сигнал АЦП.

CODE
// Управляющая структура машины состояний управляемой шаблоном
typedef struct
{
INT32U init_state;
INT32U counter;
INT32U *pattern_start_ptr; // Указатель на массив констант int являющийся цепочкой состояний (шаблоном)
// Если значение в массиве = 0xFFFF, то процесс обработки завершается
// Если значение в массиве = 0x0000, то вернуть указатель на начало цепочки
INT32U *pttn_ptr; // Текущая позиция в цепочке состояний

} T_solnd_ptrn;

// Шаблоны работы соленоидов
// ----------------------------------------------------------------------
// Шаблон состоит из массива пар слов.
// Первое слово - значение напряжения (в процентах от максимального) на текущем интервале времени
// Второе - длительность интервала времени в мс
// интервал равный 0 - означает возврат в начало шаблона
// интервал равный 65535 - означает застывание состояния

const INT32U SOLENOID1_ON[10] = { 100, 300, 25, 300, 100, 300, 25, 300, 25, 0xFFFF };
const INT32U SOLENOID2_ON[10] = { 25, 300, 100, 300, 25, 300, 100, 300, 25, 0xFFFF };
const INT32U SOLENOID_OFF[4] = { 0, 2000, 0, 0xFFFF };
// ----------------------------------------------------------------------

// Массив управляющих структур соленоидов .
T_solnd_ptrn solnd_cbl[2];


/*-------------------------------------------------------------------------------------------------------------
Инициализация машины состояний заданным шаблоном
*pttn - указатель на начало шаблона
n - индекс соленоида (0..1)
-------------------------------------------------------------------------------------------------------------*/
void Set_Solenoid_pattern(const INT32U *pttn, INT32U n)
{
if ( pttn != 0 )
{
solnd_cbl[n].pattern_start_ptr = (INT32U *)pttn;
solnd_cbl[n].pttn_ptr = (INT32U *)pttn;
Set_solenoids_voltage(*solnd_cbl[n].pttn_ptr, n);
solnd_cbl[n].pttn_ptr++;
solnd_cbl[n].counter = *solnd_cbl[n].pttn_ptr;
solnd_cbl[n].pttn_ptr++;
}
}

/*------------------------------------------------------------------------------
Вызывается из процедуры прерывания АЦП с периодичностью ADC_PERIOD
------------------------------------------------------------------------------*/
void Solenoid_automat(void)
{
static INT32U solnd_presc = 0;
INT32U duration;
INT32U voltage;
INT32U n;

solnd_presc++;

if ( solnd_presc >= (1000 / ADC_PERIOD) ) // Обработка ведется с периодом повторения - 1 мс
{
solnd_presc = 0;
for (n=0; n<2; n++)
{
// Управление состоянием сигнала соленоида
if ( solnd_cbl[n].counter )
{
solnd_cbl[n].counter--;
if ( solnd_cbl[n].counter == 0 ) // Меняем состояние сигнала при обнулении счетчика
{
if ( solnd_cbl[n].pattern_start_ptr != 0 )
{
voltage = *solnd_cbl[n].pttn_ptr;
solnd_cbl[n].pttn_ptr++;
duration = *solnd_cbl[n].pttn_ptr;
solnd_cbl[n].pttn_ptr++;
if ( duration != 0xFFFF )
{
if ( duration == 0 )
{
solnd_cbl[n].pttn_ptr = solnd_cbl[n].pattern_start_ptr;
voltage = *solnd_cbl[n].pttn_ptr;
solnd_cbl[n].pttn_ptr++;
solnd_cbl[n].counter = *solnd_cbl[n].pttn_ptr;
solnd_cbl[n].pttn_ptr++;
Set_solenoids_voltage(voltage, n);
}
else
{
solnd_cbl[n].counter = duration;
Set_solenoids_voltage(voltage, n);
}
}
else
{
// Обнуляем счетчик и таким образом выключаем обработку шаблона
Set_solenoids_voltage(voltage,n);
solnd_cbl[n].counter = 0;
}
}
else
{
Set_solenoids_voltage(0,n);
}
}
}
}

} // if ((prediv & 3)==0)
}


Сообщение отредактировал IgorKossak - Nov 28 2014, 15:58
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
psL
сообщение Nov 28 2014, 08:12
Сообщение #4


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 5-08-05
Пользователь №: 7 390



Цитата(AlexandrY @ Nov 28 2014, 10:04) *
Этот автомат применяется мною и с RTOS и без...

сложный пример. Можно проще:
CODE
enum fsm_state { IDLE, PROCESS, ERROR };

struct fsm {
enum fsm_state state;
// data...
};

static struct fsm myfsm = {
.state = IDLE,
// data startup init...
};

void fsm_init(struct fsm* fsm){
fsm->state = IDLE;
// data (re)init...
}

void fsm_proc(struct fsm* fsm){
switch(fsm->state){
case IDLE:
// do startup init ...
fsm->state = PROCESS;
break;
case PROCESS:
// do process ...
fsm->state = IDLE;
// or fsm->state = ERROR;
break;
default:
fsm->state = ERROR;
case ERROR:
// error handler
break;
}
}

Вообще без ОСи никакого контекста не будет, потому что в этом случае процесс(задача)разветвленная, но одна. В противном случае что такое контекст? Состояние регистров и стека при выполнении подпрограммы или прерывания?

Сообщение отредактировал IgorKossak - Nov 28 2014, 15:59
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 28 2014, 08:17
Сообщение #5


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(psL @ Nov 28 2014, 10:12) *
сложный пример. Можно проще:


Забавно состояние ERROR по отношению к процессу управления светодиодом.
Что бы это могло значить? biggrin.gif
Go to the top of the page
 
+Quote Post
psL
сообщение Nov 28 2014, 08:26
Сообщение #6


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 5-08-05
Пользователь №: 7 390



Цитата(AlexandrY @ Nov 28 2014, 11:17) *
Забавно состояние ERROR по отношению к процессу управления светодиодом.
Что бы это могло значить? biggrin.gif

Враги украли плату индикации wink.gif
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 28 2014, 09:09
Сообщение #7


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(psL @ Nov 28 2014, 10:26) *
Враги украли плату индикации wink.gif


Ни как ОНО узнает об этом без обратной связи то?
ERROR лишнее состояние, да и IDLE тоже.
Go to the top of the page
 
+Quote Post
psL
сообщение Nov 28 2014, 09:25
Сообщение #8


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 5-08-05
Пользователь №: 7 390



Цитата(AlexandrY @ Nov 28 2014, 12:09) *
Ни как ОНО узнает об этом без обратной связи то?

откуда вообще взялся светодиод в энтом абстрактном примере?wink.gif Придираетесь, профессор?
Цитата(AlexandrY @ Nov 28 2014, 12:09) *
ERROR лишнее состояние, да и IDLE тоже.

да, даsm.gif назовем IDLE "константа 65535" и захардкодим, чтобы джедаи не догадались sm.gif
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 28 2014, 09:57
Сообщение #9


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(psL @ Nov 28 2014, 11:25) *
откуда вообще взялся светодиод в энтом абстрактном примере?wink.gif Придираетесь, профессор?


Т.е. нынче принято обсуждать что угодно, но только не то, что спросил TC?

Цитата(psL @ Nov 28 2014, 11:25) *
да, даsm.gif назовем IDLE "константа 65535" и захардкодим, чтобы джедаи не догадались sm.gif


Боюсь вы термину IDLE придумали некое свое семантическое значение. Если оно вам помогает , ну и хорошо.
Только автоматов разных может быть много в программе и не упасётесь разными вариациями: IDLE1, IDLE2, IDLE3 ...
Go to the top of the page
 
+Quote Post
psL
сообщение Nov 28 2014, 10:55
Сообщение #10


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 5-08-05
Пользователь №: 7 390



Цитата(AlexandrY @ Nov 28 2014, 12:57) *
Т.е. нынче принято обсуждать что угодно, но только не то, что спросил TC?

ну ТС хотелось "контекста". В общем случае "контекст" может выглядеть так:
Код
struct job {
    void* data;              // "контекст"
    void  (*proc)(void*);
};

struct job jobs[] = {
   {.data=..., .proc=... }, ...
};

void job_proc(struct job* job){
   job->proc(job->data);
}

void main(){
  for(i=0; i<sizeof(jobs)/sizeof(struct job);i++)
     job_proc(&jobs[i]);
}

В качестве data и *proc м.б. struct fsm и fsm_proc из предыдущего примера с небольшой доработкой.
Или принципиально затачивать каждый пример для светодиода?
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 28 2014, 11:28
Сообщение #11


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(psL @ Nov 28 2014, 12:55) *
ну ТС хотелось "контекста". В общем случае "контекст" может выглядеть так:
Код
struct job {
    void* data;              // "контекст"
    void  (*proc)(void*);
};

struct job jobs[] = {
   {.data=..., .proc=... }, ...
};

void job_proc(struct job* job){
   job->proc(job->data);
}

void main(){
  for(i=0; i<sizeof(jobs)/sizeof(struct job);i++)
     job_proc(&jobs[i]);
}

В качестве data и *proc м.б. struct fsm и fsm_proc из предыдущего примера с небольшой доработкой.
Или принципиально затачивать каждый пример для светодиода?


А где здесь сохранение контекста?
Здесь изображен просто синхронный вызов функций с неким указателем неизвестно на что.
А если брать struct fsm как контекст задачи в применении к светодиоду, то это будет точно то же что я и продемонстрировал если вам дописать недостающий код, но будет более раздуто, так как состояниям будет выделяться дополнительная величина в управляющем шаблоне.
Go to the top of the page
 
+Quote Post
psL
сообщение Nov 28 2014, 11:48
Сообщение #12


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 5-08-05
Пользователь №: 7 390



Цитата(AlexandrY @ Nov 28 2014, 14:28) *
А где здесь сохранение контекста?

Указатель на "контекст" хранится в *data, не нужно ТС никаких downloadContext. Т.е.
Код
struct job jobs[] = {
   {.data=(void*)myfsm, .proc=fsm_proc }, ...
};

void fsm_proc(void* p){
   struct fsm* myfsm = (struct fsm*)p;
   ...
}

да, будет почти тоже самое. В этих примерах все абстрактно. Но, пмсм, так проще для понимания.

Насколько вообще понимаю суть вопроса, ТС просит обьяснить, как писать реентерабельные функции.
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 28 2014, 11:58
Сообщение #13


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(psL @ Nov 28 2014, 13:48) *
Указатель на "контекст" хранится в *data, не нужно ТС никаких downloadContext. Т.е.


Вопрос был как сохранить контекст, а не где его хранить!

И ваш ответ по сути таков: превращать любую задачу в автомат состояний и состояние хранить в структуре, которую не надо сохранять потому как она у каждой задачи своя.

Мой пример тоже основан на этом.
Но! Только для светодиодов, соленоидов и прочей односигнальной мелочи.

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



Go to the top of the page
 
+Quote Post
psL
сообщение Nov 28 2014, 22:41
Сообщение #14


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 5-08-05
Пользователь №: 7 390



Цитата(AlexandrY @ Nov 28 2014, 14:58) *
Вопрос был как сохранить контекст, а не где его хранить!
Для более сложных задач нужно применять минимум кооперативную многозадачность.

Разве как и где не взаимосвязаны? Очевидно, что данные сохраняются по указателю в структуре данных задачи. И это разжевывать не нужно.
Для "минимум коопертивной многозадачности" задача как раз таки вырождается в машину состояния. Для примера можно, например, посмотреть выход с препроцессора для protothreads


Цитата(Slash @ Nov 28 2014, 17:38) *
Извините, но это жесть что влезаю из топика "С vs C++", но этот код можно сделать еще лучше.

Непонятен смысл рефакторинга указателей. Мало того, что массив превращается в контейнер, так еще указатели превращаются в объекты с перегруженным operator []. Ради чего это сделано? Кто и кому будет кидать исключение для .at() на микроконтроллере? Или все это ради for на наборе? Как-то избыточно.
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- yanvasiij   Управление контекстом БЕЗ RTOS   Nov 21 2014, 08:04
- - 1113   ваш main() это и есть диспетчер задач. таким образ...   Nov 21 2014, 08:09
- - yanvasiij   Цитата(1113 @ Nov 21 2014, 13:09) ваш mai...   Nov 21 2014, 08:12
- - 1113   в СИ такого нет. вам надо реализовать надстройку н...   Nov 21 2014, 08:23
|- - demiurg_spb   Цитата(1113 @ Nov 21 2014, 12:23) в СИ та...   Nov 21 2014, 08:36
- - yanvasiij   Ну я вот думал, что мне предложат ассемблерный сох...   Nov 21 2014, 08:24
- - 1113   всё описано, даже на русском. а "сохраняльщик...   Nov 21 2014, 08:25
- - scifi   Цитата(yanvasiij @ Nov 21 2014, 11:04) ви...   Nov 21 2014, 08:25
|- - SSerge   Цитата(scifi @ Nov 21 2014, 15:25) Всё пр...   Nov 21 2014, 12:21
- - yanvasiij   Цитата(scifi @ Nov 21 2014, 13:25) Всё пр...   Nov 21 2014, 08:41
|- - scifi   Цитата(yanvasiij @ Nov 21 2014, 11:39) Из...   Nov 21 2014, 08:42
|- - 1113   Цитата(yanvasiij @ Nov 21 2014, 11:41) Из...   Nov 21 2014, 08:53
|- - demiurg_spb   Цитата(yanvasiij @ Nov 21 2014, 12:41) Эт...   Nov 21 2014, 09:36
- - yanvasiij   Цитата(scifi @ Nov 21 2014, 13:42) Хороше...   Nov 21 2014, 08:51
|- - ViKo   Цитата(yanvasiij @ Nov 21 2014, 11:51) РТ...   Nov 21 2014, 09:08
|- - 1113   Цитата(ViKo @ Nov 21 2014, 12:08) RTOS-ин...   Nov 21 2014, 09:34
- - yanvasiij   Цитата(1113 @ Nov 21 2014, 13:53) для так...   Nov 21 2014, 08:59
- - Golikov A.   прерывание в этом не поможет? Собственно как в РТ...   Nov 21 2014, 09:14
- - AlexandrY   Цитата(yanvasiij @ Nov 21 2014, 10:04) Мо...   Nov 21 2014, 10:08
- - MrYuran   А если немного подумать, может и не нужна никакая ...   Nov 21 2014, 12:46
|- - AlexandrY   Цитата(MrYuran @ Nov 21 2014, 14:46) А ес...   Nov 21 2014, 13:06
||- - MrYuran   Цитата(AlexandrY @ Nov 21 2014, 17:06) Не...   Nov 21 2014, 13:23
|- - scifi   Цитата(MrYuran @ Nov 21 2014, 15:46) А ес...   Nov 21 2014, 15:46
|- - jcxz   Цитата(WitFed @ Nov 27 2014, 20:04) Также...   Nov 28 2014, 04:02
|- - Slash   Цитата(AlexandrY @ Nov 28 2014, 10:04) Эт...   Nov 28 2014, 14:38
- - Golikov A.   ага супер луп на конечных автоматах называется... ...   Nov 27 2014, 15:01
- - Golikov A.   ЦитатаНепонятно - почему не нужны критические секц...   Nov 28 2014, 07:49
|- - jcxz   Цитата(Golikov A. @ Nov 28 2014, 13:49) п...   Nov 28 2014, 11:06
- - Golikov A.   fsm->state можно и в прерывании сменить на ERRO...   Nov 28 2014, 09:11
|- - AlexandrY   Цитата(Golikov A. @ Nov 28 2014, 11:11) f...   Nov 28 2014, 09:18
- - Golikov A.   ЦитатаЭто верно только в одном частном случае - ко...   Nov 28 2014, 14:07
|- - jcxz   Цитата(Golikov A. @ Nov 28 2014, 20:07) К...   Nov 28 2014, 15:34
- - Golikov A.   чего то я видать безнадежно устарел Кодfor (co...   Nov 28 2014, 15:04
|- - Slash   Сколько не читал битв "C vs C++", почему...   Nov 28 2014, 16:07
|- - jcxz   Цитата(Slash @ Nov 28 2014, 22:07) Очень ...   Nov 28 2014, 16:26
- - Golikov A.   вопрос в другом. Разве в С++ есть for без ;; ? for...   Nov 28 2014, 15:49
- - Golikov A.   ЦитатаСтоит отметить, что хоть range-based for и я...   Nov 28 2014, 16:15
- - yanvasiij   Чтобы внести конкретики. Зачем мне это надо и поче...   Dec 1 2014, 07:29
|- - scifi   Цитата(yanvasiij @ Dec 1 2014, 10:29) Зач...   Dec 1 2014, 07:55
- - yanvasiij   Цитата(scifi @ Dec 1 2014, 12:55) Кстати,...   Dec 1 2014, 08:12
- - scifi   Цитата(yanvasiij @ Dec 1 2014, 11:12) На ...   Dec 1 2014, 09:01


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 9th August 2025 - 02:20
Рейтинг@Mail.ru


Страница сгенерированна за 0.01622 секунд с 7
ELECTRONIX ©2004-2016