Как одновременно выполнить функцию без использования потоков

У меня есть серверная программа, которая отправляет данные клиентов другому, который их обрабатывает. Но поскольку выполнение функции может занять много времени и не позволяет программе работать с данными других клиентов, я хочу одновременно выполнять ту же функцию над данными других клиентов, не используя pthreads и не создавая процессы.

Я пытался создать что-то, что может сделать это, но это уродливо и, конечно, не лучшим образом. Вот мой код:

#include <stdio.h>
#include <string.h>
#include <vector>

struct userdata {
int rt; //The 'func' function uses it to resume work where it returned the last time
int len; //The length of 'data'
char data[16384]; //Client's data
};

int func(userdata *ud)
{
//The gotos are here to jump to the code where the function returned the last time
if(ud->rt==1)goto P1;
if(ud->rt==2)goto P2;

ud->len=0;

//Code to calculate the length of 'data'
while(ud->data[ud->len]!=0)
{
ud->rt=1; //Set to 1 to indicate where to resume execution the next time we will process the same data
return 0;
P1:
ud->len++;
}
// Work
ud->rt=2;
return 0;
P2:
// Work

return 1;
}

int main(int argc, char *argv[])
{
userdata ud;
memset(ud.data,1,16383);
ud.data[16383]=0;

std::vector<userdata> vec;
for(int i=0;i!=200;i++)vec.push_back(ud); //Add 200 times the structure in the vector
unsigned int Sz=vec.size(); //I'll use Sz in the for loop to avoid calling size()

bool Loop=true;
do
{
for(int i=0;i!=Sz;i++)
{
if( func(&vec.at(i))==1) //If the function returned 1 this means that there's no more work to do
{
printf("str length = %i\n",vec.at(i).len); //Display the result
vec.erase(vec.begin() + i); //Remove element from vector because there's no more work to do
i--, Sz--; //Decrement Sz (size of the vector) and i (vector index) to avoid out_of_range exception
if(Sz==0)Loop=false; //If there are no elements in the vector, leave Loop
}
}
}
while(Loop);

return 0;
}

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

2

Решение

Не пытайтесь написать свою собственную универсальную библиотеку потоков, это будет дороже, чем pthreads. Вместо этого разделите проблему, используя знания вашей конкретной проблемы. Найти место, где это делает смысл к

Я предполагаю, что у вас уже есть основной цикл, который просто вызывает select/poll/epoll кучка. Если у вас еще нет тайм-аута, начните использовать его, чтобы вы могли хранить набор дополнительных, синхронизированных и даже триггеров в куче.

Затем в каждом вычислении после определенного числа итераций останавливайте расписание для вызова функции + данные. Использовать ток время (в конце, в отличие от времени начала текущего события таймера). Предполагая, что время действительно истекло, диспетчер таймера сначала завершит все вычисления для самого старого тика, а затем перейдет к следующему шагу нового тика (приблизительно в циклическом планировщике). Обратите внимание, что вы делаете не Вы хотите, чтобы размер среза был слишком маленьким, иначе издержки на переключение задач начнут доминировать.

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

1

Другие решения

Не пытайтесь изобретать велосипед. Механизм заправки сложен. Все, что вы делаете, будет работать хуже и медленнее, чем ваша система.

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

0

По вопросам рекламы [email protected]