The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

форумы  помощь  поиск  регистрация  майллист  ВХОД  слежка  RSS
"Сокеты.Выдление буфера для обработки соединения потоком"
Вариант для распечатки Архивированная нить - только для чтения! 
Пред. тема | След. тема 
Форумы Программирование под UNIX (Public)
Изначальное сообщение [Проследить за развитием треда]

"Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от max2057 Искать по авторуВ закладки on 01-Июл-03, 17:58  (MSK)
Я пишу сервер сокетный с использованием PThreads.
После приема соединения сокет передается создаваемому потоку, который и работает с эти клиентом.
Так вот буфер где выделять?
вот так:
client_thread(..)
{
char * buf = malloc(..);
  send..
  ...
  recv..
}

или выделять в главном потоке?

  Рекомендовать в FAQ | Cообщить модератору | Наверх

 Оглавление

Индекс форумов | Темы | Пред. тема | След. тема
Сообщения по теме

1. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от XMan Искать по авторуВ закладки on 01-Июл-03, 23:21  (MSK)
А какая разница ? Если тебе не нужно, чтобы к этому буферу имел доступ основной поток, то как угодно :)
  Рекомендовать в FAQ | Cообщить модератору | Наверх

2. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от max2057 Искать по авторуВ закладки on 02-Июл-03, 10:25  (MSK)
Я про то, чтобы при запуске следующего потока указатель на буфер не менялся для предыдущего потока - чтоб код был типа thread-safe
  Рекомендовать в FAQ | Cообщить модератору | Наверх

3. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от XMan Искать по авторуВ закладки on 02-Июл-03, 15:27  (MSK)
Ну так если ты объявляешь переменную внутри функции, то сколько бы ты её не вызывал, в каждом экземпляре будет своя область памяти (в частности, стека) не зависимо от того, является ли функция потоком или нет. Единственное исключение - это статическая переменная (static ....) - она одна для всех, но я не уверен в том, как она будет работать в потоках.
  Рекомендовать в FAQ | Cообщить модератору | Наверх

8. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от sas emailИскать по авторуВ закладки on 04-Июл-03, 09:15  (MSK)
>Ну так если ты объявляешь переменную внутри функции, то сколько бы ты
>её не вызывал, в каждом экземпляре будет своя область памяти (в
>частности, стека) не зависимо от того, является ли функция потоком или
>нет. Единственное исключение - это статическая переменная (static ....) - она
>одна для всех, но я не уверен в том, как она
>будет работать в потоках.

С блокировкой будет

  Рекомендовать в FAQ | Cообщить модератору | Наверх

4. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от Parish Искать по авторуВ закладки on 03-Июл-03, 00:32  (MSK)
зафлудят твой сервер - где стока памяти возьмешь?
  Рекомендовать в FAQ | Cообщить модератору | Наверх

5. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от Alex Искать по авторуВ закладки on 03-Июл-03, 10:43  (MSK)
>зафлудят твой сервер - где стока памяти возьмешь?
Попробуйте передавать в thread дополнительно порядковый номер. Очень пригодиться при создании log. Память лучше выделять в thread. Удобно для случая, когда кол-во thread не фиксированы и Вы изменяете нагрузку.


  Рекомендовать в FAQ | Cообщить модератору | Наверх

6. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от XMan Искать по авторуВ закладки on 03-Июл-03, 15:24  (MSK)
Можно использовать tid в качестве порядковогономера номера :)
  Рекомендовать в FAQ | Cообщить модератору | Наверх

7. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от sas emailИскать по авторуВ закладки on 04-Июл-03, 09:13  (MSK)
>Можно использовать tid в качестве порядковогономера номера :)

К сожалению нельзя pthread_t is opaque type. Т.е. зависит от реализации

Успехов
--- sas

  Рекомендовать в FAQ | Cообщить модератору | Наверх

9. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от max2057 Искать по авторуВ закладки on 08-Июл-03, 10:34  (MSK)
я экспериментик провел
void my_thread(void * arg)
{
  char * p = malloc(1024);
  printf("%s:p=%X",(char)arg,(int)p);
  free(p);
}

берем создаем 2 потока из этой ф-и и оба потока печатают одно и тоже значение p, что-то вроде
th1:p=8567DE23
th2:p=8567DE23
это как? если p - локальная переменная , то значения должны быть разные.


  Рекомендовать в FAQ | Cообщить модератору | Наверх

10. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от Jamper emailИскать по авторуВ закладки on 08-Июл-03, 10:40  (MSK)
а чем тебе не нравится вариант приемно передающего буфера вида
char buf[maxline];
  Рекомендовать в FAQ | Cообщить модератору | Наверх

11. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от sas emailИскать по авторуВ закладки on 08-Июл-03, 11:02  (MSK)
>я экспериментик провел
>void my_thread(void * arg)
>{
>  char * p = malloc(1024);
>  printf("%s:p=%X",(char)arg,(int)p);
>  free(p);
>}
>
>берем создаем 2 потока из этой ф-и и оба потока печатают одно
>и тоже значение p, что-то вроде
>th1:p=8567DE23
>th2:p=8567DE23
>это как? если p - локальная переменная , то значения должны быть
>разные.

Существуют следующие правила:

1) Все "видимые/доступные" переменные в порождающем потоке ПЕРЕД вызовом pthread_create   будут "видимы/доступны" новому (порожденному) потоку После pthread_create могут не быть видны

2) Все переменные доступные потоку когда разблокируется мьютекс (  ТОЛЬКО ДО РАЗБЛОКИРОВАНИЯ) будут видимы и доступны для потока который этот мьютекс заблокирует

3) Все переменные которые видимы/доступны потоку когда он умирает (ТОЛЬКО ДО СМЕРТИ) будут видимы/доступны потоку который сделает join

4) Все что доступно потоку ДО сигнала/броадкаста будет видимо/доступно для потока который проснется по этому сигналу/броадкасту

Так что в Вашем случае все правильно согласно правилу 1.

Успехов
--- sas

  Рекомендовать в FAQ | Cообщить модератору | Наверх

12. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от max2057 Искать по авторуВ закладки on 08-Июл-03, 16:22  (MSK)
спасибо
  Рекомендовать в FAQ | Cообщить модератору | Наверх

13. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от XMan Искать по авторуВ закладки on 08-Июл-03, 20:32  (MSK)
Чего-то я не вкурил.
Имеется конструкция:

pthread_create(....); // поток 1
pthread_create(....); // поток 2

Если я выделил память в первом потоке, потом прошло создание второго такого же потока, то второй видит данные первого ?

Тем более, если второй поток выделяет память в ту же переменную, то возможны два варианта:

(a) - адреса должны быть разными;
(б) - второй поток забьет данные первого; при этом получаем классическую утечку памяти.
Дополнительный вариант (в) - второй поток видит данные первого до тех пор, пока не сделает свой "malloc" (что-то наподобии "malloc" -> "fork", только по указанному адресу можно еще и обратиться из потомка). В этом случае возвращаемся к варианту (a).

Вариант (a) может зависеть от реализации потоков. Если память выделяется не в контексте процесса, а в контексте потока, то вполне возможны 2 одинаковых адреса для разных потоков.  В смысле - одинаковые адреса для потоков на самом деле являются разными адресами для процесса. Аналогия - два разных процесса могут иметь одинаковый адрес динамической памяти, но реально их данные не пересекаются.

Помоему так. Где я ошибаюсь ?

PS. Как по мне, так одинаковые адреса получаются потому, что первый поток успевает освободить память до того, как второй пытается её выделить. Интересно, если поставить, например, "sleep(5)" перед "free(p)", то какие будут результаты ?

  Рекомендовать в FAQ | Cообщить модератору | Наверх

15. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от sas emailИскать по авторуВ закладки on 09-Июл-03, 07:13  (MSK)
>Чего-то я не вкурил.
>Имеется конструкция:
>
>pthread_create(....); // поток 1
>pthread_create(....); // поток 2
>
>Если я выделил память в первом потоке, потом прошло создание второго такого
>же потока, то второй видит данные первого ?

НЕТ Перечитайте правило 1, согласно ему поток 0 (порождающий) и переменные видимые в потоке 0 могут быть  ВИДИМЫ (И ПЕРЕДАНЫ) в потоках 1 и 2. Вот если поток 1 создаст поток 2 (pipe workflow) и передаст ему адрес своей локальной переменной, то поток 2 ее увидит.  В противном случае поток 2 ничего не знает о потоке1. И стек и динамическая память (как Вы уже писали) ЛОКАЛЬНЫ для потока.
Глобальные (статические и нет) переменные видны для всех потоков без явной передачи (см пример в конце ответа)

>
>Тем более, если второй поток выделяет память в ту же переменную, то
>возможны два варианта:
>
>(a) - адреса должны быть разными;

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

>(б) - второй поток забьет данные первого; при этом получаем классическую утечку
>памяти.

Рассмотрим следующий  пример в однопоточной программе:

char* ptr = (char*)malloc( 100 );
ptr = (char*)malloc( 50 );
free( ptr );

Потеряли 100 байт от первого malloc

Или
char* ptr = strdup( "XXXXXXXXXXX" );
assert( ptr != NULL );
int l = strlen( ptr );
strncpy( ptr, "CCCCCCCCCCC", l );
ptr[ l - 1 ] = '\0';

Перезаписали данные.

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

>Дополнительный вариант (в) - второй поток видит данные первого до тех пор, пока не сделает свой "malloc" (что-то наподобии "malloc" -> "fork", только по указанному адресу можно еще и обратиться из потомка). В этом случае возвращаемся к варианту (a).
>
>Вариант (a) может зависеть от реализации потоков. Если память выделяется не в
>контексте процесса, а в контексте потока, то вполне возможны 2 одинаковых
>адреса для разных потоков.  В смысле - одинаковые адреса для
>потоков на самом деле являются разными адресами для процесса. Аналогия -
>два разных процесса могут иметь одинаковый адрес динамической памяти, но реально
>их данные не пересекаются.
>
>Помоему так. Где я ошибаюсь ?
>

Не думаю. Т.к. потоки принадлежат одному процессу, то и виртуальная память процесса используется ВСЕМИ потоками Это означает что адреса будут разными
При создании потока резервируется память, принадлежащая процессу, которая и используется для его (потока) стека и динамической памяти.

>PS. Как по мне, так одинаковые адреса получаются потому, что первый поток
>успевает освободить память до того, как второй пытается её выделить. Интересно,
>если поставить, например, "sleep(5)" перед "free(p)", то какие будут результаты ?
>

Вот пример одинаковых адресов (Только скелет кода. Могут быть ошибки и опечатки)

/*
**** thread1.c
**
**   Demo for variable visibility (rule 1)
*/

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>

#define S "AAAAAAAAAAAAAAAAAAAAAAAAAAA"
#define S1 "XXXXXXXXXXXXX"
#define S2 "RRRRRRRRRRRRR"

pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;

void fatal_err( int res, const char* txt )
{
fprintf( stderr, "FATAL ERROR: Status=%d\t%s... Exiting...", res, txt );
exit( EXIT_FAILURE );
}

void* thread( void* thr_arg, const char* thr_name, const char* new_str )
{
int res;
char* sptr = (char *)thr_arg;

res = pthread_mutex_lock( &g_mutex );
if ( res != 0 )
fatal_err( res, "thread::pthread_mutex_lock failed" );

fprintf( stdout, "%s:: Recieved address=%p value=[%s]\n", thr_name, sptr, sptr );

res = pthread_mutex_unlock( &g_mutex );
if ( res != 0 )
fatal_err( res, "thread::pthread_mutex_unlock failed" );

       /* Below completely new pointer value assigned to sptr
         * thr_arg value is not affected
         */
sptr = strdup( new_str );
assert( sptr != NULL );
fprintf( stdout, "%s:: after strdup address=%p value=[%s]\n", thr_name, sptr, sptr );

return (void *)sptr;
}

void* test_thread_1( void* ptr )
{
return thread( ptr, "test_thread_1", S1 );
}

void* test_thread_2( void* ptr )
{
return thread( ptr, "test_thread_2", S2 );
}

int main( int argc, char* argv[] )
{
pthread_t thr1, thr2;
char* s1 = strdup( S );
int res;
extern int errno;
char* thr1_res = NULL, *thr2_res = NULL;

if ( s1 == NULL )
fatal_err( errno, "main:: s1 allocation failed" );

fprintf( stdout, "main:: s1 address=%p value=[%s]\n", s1, s1 );

res = pthread_create( &thr1, NULL, test_thread_1, (void *)s1 );
if ( res != 0 )
fatal_err( res, "main::pthread_create( test_thread_1 ) failed" );

res = pthread_create( &thr2, NULL, test_thread_2, NULL );
if ( res != 0 )
fatal_err( res, "main::pthread_create( test_thread_2 ) failed" );

res = pthread_join( thr1, (void**)&thr1_res );
assert( thr1_res != NULL );

res = pthread_join( thr2, (void**)&thr2_res );
assert( thr1_res != NULL );

fprintf( stdout, "main:: s1 after join address=%p value=[%s]\n", s1, s1 );
fprintf( stdout, "main:: thr1_res after join address=%p value=[%s]\n", thr1_res, thr1_res );
fprintf( stdout, "main:: thr2_res after join address=%p value=[%s]\n", thr2_res, thr2_res );

free( s1 );
free( thr1_res );
free( thr2_res );

return 0;
}

  Рекомендовать в FAQ | Cообщить модератору | Наверх

16. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от sas emailИскать по авторуВ закладки on 09-Июл-03, 07:20  (MSK)
Когда я говорю о динамической памяти потока я имею в виду, что переменные обеспечивающие доступ к динамической памяти локальны для потока Содержимое динамической памяти принадлежит процессу. Именно поэтому даже когда поток завершился мы можем использовать данные из heap

Успехов
--- sas

  Рекомендовать в FAQ | Cообщить модератору | Наверх

18. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от XMan Искать по авторуВ закладки on 09-Июл-03, 22:26  (MSK)
Это-то я всё понял. Я только не понял, каким образом "правило 1" объясняет совпадение адресов в разных потоках, при условии, что каждый из них выделяет память для локальной переменной :) Ведь кусок кода был такой:

char * p = malloc(1024);
printf("%s:p=%X",(char)arg,(int)p);
free(p);

То есть, вывод адреса на экран происходил уже после того, как локальная переменная потока получила его от "malloc()". Я потому в "PS" сове представление происходящего и написал :)

  Рекомендовать в FAQ | Cообщить модератору | Наверх

19. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от sas emailИскать по авторуВ закладки on 10-Июл-03, 00:36  (MSK)
>Это-то я всё понял. Я только не понял, каким образом "правило 1"
>объясняет совпадение адресов в разных потоках, при условии, что каждый из
>них выделяет память для локальной переменной :) Ведь кусок кода был
>такой:
>
>char * p = malloc(1024);
>printf("%s:p=%X",(char)arg,(int)p);
>free(p);
>
>То есть, вывод адреса на экран происходил уже после того, как локальная
>переменная потока получила его от "malloc()". Я потому в "PS" сове
>представление происходящего и написал :)

Вопрос был:
========================
я экспериментик провел
void my_thread(void * arg)
{
  char * p = malloc(1024);
  printf("%s:p=%X",(char)arg,(int)p);
  free(p);
}

берем создаем 2 потока из этой ф-и и оба потока печатают одно и тоже значение p, что-то вроде  
th1:p=8567DE23
th2:p=8567DE23
это как? если p - локальная переменная , то значения должны быть разные.
=========================

Ключевая фраза:

"берем создаем 2 потока из этой ф-и и оба потока печатают одно и тоже значение p"

:)

Как я понял что-то вроде

void my_thread(void * arg)
{
  char * p = malloc(1024);
  printf("%s:p=%X",(char)arg,(int)p);
  pthread_create( &thr, NULL, thread1, (void*)p );
  pthread_create( &thr, NULL, thread2, (void*)p );
  /***free(p);***/
}

Если автор имел в виду создание 2-х потоков НЕ ИЗ этой, а с использованием этой функции:

pthread_create( &thr, NULL, my_thread, NULL );
pthread_create( &thr, NULL, my_thread, NULL );

то Вы были правы. Из-за использования уже освобожденной памяти (1-ый вызов my_thread уже сделал free) один и тот же адрес может быть присвоен двум локальным переменным в разных потоках. При этом они (переменные потоков) одновременно не живут

void my_thread(void * arg)
{
  char * p = malloc(1024);
  printf("%s:p=%X",(char)arg,(int)p);
  sleep( 10 );
  free(p);
}

и скорее всего адреса будут разными

Прошу прощения за разночтение  :(

Успехов
--- sas

          

  Рекомендовать в FAQ | Cообщить модератору | Наверх

14. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от proff emailИскать по авторуВ закладки on 09-Июл-03, 00:57  (MSK)
попробуйте сделать так:

printf("%s:p=%X",(char*)arg,(int)p);


p.s.

1. malloc() отводит блок памяти в куче, что не относится к thread'ам никаким образом (куча по умолчанию для всех одна). к thread'ам относится только указатель на блок памяти char* p, который уникален для каждого thread'а, в силу того, что функция my_thread() выполняется параллельно, а это локальная переменная.

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

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

  Рекомендовать в FAQ | Cообщить модератору | Наверх

17. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от max2057 Искать по авторуВ закладки on 09-Июл-03, 10:11  (MSK)
Буфер вынес в tcb(описал структуру и для каждого потока выделяю отдельную структурную переменную).
Видите ли, если ставить мутекс_локи или заставлять один поток спать, то значения указателя у каждого потока свое, одного не пойму - если это локальная переменная потока, то почему один поток интерферирует с другим -стеки-то у них по идее разные?

  Рекомендовать в FAQ | Cообщить модератору | Наверх

20. "Сокеты.Выдление буфера для обработки соединения потоком"
Сообщение от XMan Искать по авторуВ закладки on 10-Июл-03, 12:11  (MSK)
> одного не пойму - если это локальная переменная потока, то почему один поток интерферирует с другим -стеки-то у них по идее разные?

Посмотри соседнюю ветку - там объяснение есть :)

  Рекомендовать в FAQ | Cообщить модератору | Наверх


Удалить

Индекс форумов | Темы | Пред. тема | След. тема
Пожалуйста, прежде чем написать сообщение, ознакомьтесь с данными рекомендациями.




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру