LINUX.ORG.RU

Передача параметров из одного класса в другой

 


0

2

Приветствую. Есть класс-сервер, в котором при подключении нового клиента создается объект-клиент для каждого подключения. В классе клиента идет обработка каких-нибудь данных и прочее и обработанные данные надо как-то передать или классу-сервера и еще куда либо. Сейчас использую интерфейсы, к примеру, как-то так:

class IServer
{
  virtual void setData(int newData) = 0;
}

class CClient
{
public:
  CLient(IServer *parent): m_parent(parent) {}
private:
   IServer *m_parent;
  void processData()
  {
     parent->setData(data);
  }
}

класс-сервера:

class CServer : public IServer
{
public:
  CServer() {}
  void setDate(int newData) {/*do smth*/}
  void newConnection();
}

void CServer::newConnection()
{
  CClient *client = new CClient(this);
  /* do smth */
}

На сколько такой вариант оправдан?


На сколько такой вариант оправдан?

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

XMs ★★★★★
()
Ответ на: комментарий от hound

Однопоточный сервер? Не, ну на еполле можно состряпать, но по факту такие в продакшне не выживают обычно.

DELIRIUM ☆☆☆☆☆
()
Ответ на: комментарий от XMs

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

hound
() автор топика
Ответ на: комментарий от hound

Оправдано в двух случаях:

1) Если есть подозрение, что клиенту надо будет уметь работать с разными серверами (например, с реальным и с заглушкой из юнит-теста);

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

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

vzzo ★★★
()
Последнее исправление: vzzo (всего исправлений: 1)
Ответ на: комментарий от vzzo

— нет

Да.

Все он правильно сделал. Даже для маленьких программ такой подход не позволяет генерить говнокод. Больше ифейсов хороших и разных!

anonymous
()

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

Deleted
()
Ответ на: комментарий от anonymous

В данном случае от говнокода может спасти следствие введения интерфейса — необходимость подумать о правильном разделении public и private частей сервера. Само по себе введение интерфейса не влияет на генерацию говнокода (разве что в положительную сторону при оверинжиниринге или при необходимости чего-то протечь свозь дырку в абстракции).

vzzo ★★★
()
Ответ на: комментарий от hound

оправдано ли использование интерфейс для передачи информации из одного класса в другой по такой схеме

Не только оправдано, а так и надо делать.

no-such-file ★★★★★
()

CClient *client = new CClient(this);

А вот так не делай, используй фабрику.

no-such-file ★★★★★
()
Ответ на: комментарий от XMs

Ты случаем не знаешь, как лучше? Создавать в каждом соединении новый поток, или новый процесс? Процессы же ограничены по количеству запущенных. Как это делают на таких как apache или nginx? Или на другом сервере, где нужно получать много соединений?

u0atgKIRznY5
()
Ответ на: комментарий от u0atgKIRznY5

Общего решения не назову. Poco, например, на каждый сокет создаёт поток, как я понял из документации, но по мне это очень растратное решение. Здесь лучше сработает своя обёртка над select/poll/{epoll,kqueue} + thread pool обработчиков. Хотя наверняка те, кто работает с сетью, могут предложить лучшее решение

XMs ★★★★★
()

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

По поводу юнит-тестов — тоже не оправдано. Для юнит-теста можно просто реализовать логику в другом cpp файле (на уровне системы сборки).

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

com
()
Ответ на: комментарий от u0atgKIRznY5

Создавать в каждом соединении новый поток, или новый процесс?

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

Процессы же ограничены по количеству запущенных.

Как и потоки. С точки зрения системы это почти одно и то же. Просто потоки полегче (их иногда так и называют «облегчёнными процессами»). И pid они имеют уникальный из общего пула.

#include <pthread.h>
#include <unistd.h>

void* thread(void* nul)
{ 
  while(1) sleep(5);
  return 0;
}

int main(int argc, char** argv)
{
  pthread_t pth;
  pthread_create(&pth, 0, thread, 0);
  while(1) sleep(5);
  return 0;
}
$ gcc -o pthread -pthread -Wall pthread.c
$ ./pthread &
[1] 19517
$ ps -eLf | grep pthread
19517 23643 19517  0    2 04:02 pts/9    00:00:00 ./pthread
19517 23643 19518  0    2 04:02 pts/9    00:00:00 ./pthread
19532 23643 19532  0    1 04:02 pts/9    00:00:00 grep pthread
$ kill 19517
[1]+  Завершено      ./pthread
$ ps -eLf | grep pthread
19571 23643 19571  0    1 04:04 pts/9    00:00:00 grep pthread
$
aureliano15 ★★
()

Ты забыл:

#include <boost>
rupert ★★★★★
()
Ответ на: комментарий от aureliano15

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

u0atgKIRznY5
()
Ответ на: комментарий от u0atgKIRznY5

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

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

Я имею ввиду что когда запущен процесс и он создаёт потоки, то общее время, которое выделено процессу, будет делиться между этим процессом и всеми его потоками. Но если процесс создаст другой процесс, будет ли другой процесс получать своё время для выполнения, не зависимо от порождённого процесса?

u0atgKIRznY5
()
Ответ на: комментарий от aureliano15

Будет ли дочерний процесс получать своё время для выполнения, независимо от родительского процесса? Хотя откуда ты можешь знать.

u0atgKIRznY5
()
Ответ на: комментарий от u0atgKIRznY5

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

Это может зависеть от реализации. В той или иной конкретной системе это легко проверить. Слегка модифмцируем программу pthread.c:

#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <stdlib.h>

void* thread(void* nul)
{
  int i=0;
  while(1) { printf("pid=%i,tid=%i\n", getpid(), (int)syscall(SYS_gettid)); ++i; if(i%50==0) sleep(1); }
  return 0;
}

int main(int argc, char** argv)
{
  int n=1;
  if(argc>1)
   n=atoi(argv[1]);
  pthread_t pth;
  while(n--) pthread_create(&pth, 0, thread, 0);
  while(1) sleep(5000);
  return 0;
}

Теперь она создаёт столько потоков, сколько указано в параметре, по умолчанию 1, как и раньше. А потоки выводят в стандартный вывод свой pid (process id) и tid (thread id, тот же pid, но для каждого потока свой, для главного совпадает с pid). Для чистоты эксперимента выводят свои pid'ы они без паузы, но через 50 итераций всё-таки на секунду засыпают, чтоб полностью не загрузить процессор и чтоб в консоли можно было хоть что-то ввести.

Дальше компилируем, запускаем и через некоторое время прибиваем:

$ gcc -o pthread -pthread -Wall pthread.c
$ ./pthread >> pthread.log & ./pthread 5 >> pthread.log & sleep 20; killall pthread
[1] 6132
[2] 6133
[1]-  Завершено      ./pthread >> pthread.log
[2]+  Завершено      ./pthread 5 >> pthread.log

У первого процесса с 1 потоком pid 6132, а у второго с 5 потоками — 6133. Приоритеты у обоих одинаковые, установленные по умолчанию. Всё писалось в один общий лог. Теперь смотрим статистику:

$ cat pthread.log | grep 6132 | wc -l; cat pthread.log | grep 6133 | wc -l;
910
5234
$ expr 5234 / 910
5

Как видим, время выделяется на потоки, а не на процессы. Точнее, Linux в данном случае не видит между ними разницы. Как и ожидалось, 5 потоков получили в 5 раз больше времени, чем 1. Так что хочешь, делай процессы, а хочешь — потоки. Вот если задать им разные приоритеты, то разница будет. Однако, так это работает в Linux. В других ОС может работать по-другому.

Хотя откуда ты можешь знать.

Когда я чего-то не знаю, — я проверяю. В данном случае я знал, но не готов был поручиться на 100%, поэтому проверил свои знания на практике.

aureliano15 ★★
()
Ответ на: комментарий от u0atgKIRznY5

Есть native threads и green threads. Native этот потоки операционной системы, которые диспетечеризуются ядром операционки и могут работать параллельно одновременно на многоядерных или многопроцессорных системах, такие потоки фактически равны процессам за исключением того что у них общее адресное пространство. Green threads это не настоящие потоки и они делят между собой время настоящего потока. Есть смешанные схемы, когда на каждый native поток делается несколько green.

Posix threads и потоки в питоне и java это native. А например в руби потоки уже green почти всегда

Nastishka ★★★★★
()
Ответ на: комментарий от Nastishka

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

Nastishka ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.