#c #память #unix #freebsd #pthread
Всем добрый день!
Хотелось бы обсудить следующую проблему : в программе средствами библиотеки pthread
создается поток, ОС выделяет ему некоторый обьем памяти на стек и т.п., после того,
как данный поток отработал и завершился, из другого потока вызывается pthread_join(),
забирающая код возврата. При этом, не заметно, чтобы память, выделенная для данного
потока, освобождалась (при вызове pthread_create() выделилось порядка 100 кб, из которых
ничего не освободилось ни после return(), ни после pthread_join()). Кто-нибудь может
пояснить, почему? Я что-то не так делаю, или это может быть обусловлено поведением ОС ?
Ответы
Ответ 1
@margosh, я тоже (солидарно с @mikillskegg и почти интуитивно) считаю, что память,
которую брал поток, используется повторно. Иллюстрацию приведу прямо здесь.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fatal(msg) ({perror(msg); exit(-1);})
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int nth = 0;
void *
thcli (void *a)
{
pthread_mutex_lock(&lock);
nth--;
pthread_mutex_unlock(&lock);
return (void *)1;
}
int
main (int ac, char *av[])
{
int i, n = av[1]? atoi(av[1]):100;
if (n < 1)
n = 100;
pthread_t th[n];
void *res[n];
char buf[100];
do {
pthread_mutex_lock(&lock);
for (i = 0; i < n; i++) {
if (pthread_create (&th[i], NULL, thcli, NULL))
fatal("create");
nth++;
}
printf ("run %d nth = %d\n",i,nth);
pthread_mutex_unlock(&lock);
for (i = 0; i < n; i++) {
if (pthread_join (th[i], &res[i]))
fatal("join");
}
printf ("join %d nth = %d\nAgain ?\n",i,nth);
} while (fgets(buf,sizeof(buf),stdin), buf[0] == 'y');
exit (puts("Bye") == EOF);
}
Обилия инклюдов не пугайтесь, большая часть на нужны, просто скопировал для этого
тестика из другой программы.
А вот и иллюстация
avp@avp-xub11:~/src/ig/tst$ gcc th.c -pthread
.....
avp@avp-xub11:~/src/ig/tst$ ./a.out 381
create: Cannot allocate memory
avp@avp-xub11:~/src/ig/tst$ ./a.out 380
run 380 nth = 380
join 380 nth = 0
Again ?
y
run 380 nth = 380
join 380 nth = 0
Again ?
y
run 380 nth = 380
join 380 nth = 0
Again ?
y
run 380 nth = 380
join 380 nth = 0
Again ?
.
Bye
avp@avp-xub11:~/src/ig/tst$ ./a.out 380
run 380 nth = 380
join 380 nth = 0
Again ?
y
run 380 nth = 380
join 380 nth = 0
Again ?
.
Bye
avp@avp-xub11:~/src/ig/tst$ ./a.out 381
create: Cannot allocate memory
avp@avp-xub11:~/src/ig/tst$
IMHO видно, что если ресурса почти достаточно, то после завершения потоков он опять
высвобождается и повторно используется (по крайней мере в такой же ситуации).
UPD-1
@margosh, у меня в линуксе не растет. Добавил функцию
// returns second field for last line selected by 'what'
static int
pri_mem (int pid, char **what)
{
char path[1000];
int res = 0;
sprintf (path,"/proc/%d/status",pid);
FILE *in = fopen(path,"r");
if (!in) {
perror(path);
return;
}
while (fgets(path,1000,in)) {
char **w = what;
while (*w) {
if (strncasecmp(path,*w,strlen(*w)) == 0) {
fputs(path,stdout);
char dummy[1000];
sscanf(path,"%s %d",dummy,&res);
break;
}
w++;
}
}
fclose(in);
return res;
}
и чуть изменил main(), теперь печатает память перед каждым циклом
avp@avp-xub11:~/src/ig/tst$ gcc th.c -pthread
avp@avp-xub11:~/src/ig/tst$ ./a.out 380
VmPeak: 2252 kB
VmSize: 2252 kB
VmHWM: 312 kB
VmRSS: 312 kB
VmStk: 136 kB
run 380 nth = 380
loop 0: join 380 nth = 0
Exit ?
VmPeak: 3116732 kB
VmSize: 35044 kB
VmHWM: 2180 kB
VmRSS: 680 kB
VmStk: 136 kB
run 380 nth = 380
loop 1: join 380 nth = 0
Exit ?
VmPeak: 3116736 kB
VmSize: 35044 kB
VmHWM: 2192 kB
VmRSS: 692 kB
VmStk: 136 kB
run 380 nth = 380
loop 2: join 380 nth = 0
Exit ?
VmPeak: 3116736 kB
VmSize: 35044 kB
VmHWM: 2192 kB
VmRSS: 692 kB
VmStk: 136 kB
run 380 nth = 380
loop 3: join 380 nth = 0
Exit ?
и дальше
VmPeak: 3116736 kB
VmSize: 35044 kB
VmHWM: 2192 kB
VmRSS: 692 kB
VmStk: 136 kB
run 380 nth = 380
loop 29: join 380 nth = 0
Exit ?
VmPeak: 3116736 kB
VmSize: 35044 kB
VmHWM: 2192 kB
VmRSS: 692 kB
VmStk: 136 kB
run 380 nth = 380
loop 30: join 380 nth = 0
Exit ?
VmPeak: 3116736 kB
VmSize: 35044 kB
VmHWM: 2192 kB
VmRSS: 692 kB
VmStk: 136 kB
run 380 nth = 380
loop 31: join 380 nth = 0
Exit ?
y
Bye
avp@avp-xub11:~/src/ig/tst$
IMHO не растет. Попробуем с небольшим количеством потоков
avp@avp-xub11:~/src/ig/tst$ ./a.out 30
VmPeak: 2252 kB
VmSize: 2252 kB
VmHWM: 316 kB
VmRSS: 316 kB
VmStk: 136 kB
run 30 nth = 30
loop 0: join 30 nth = 0
Exit ?
VmPeak: 248132 kB
VmSize: 35044 kB
VmHWM: 728 kB
VmRSS: 628 kB
VmStk: 136 kB
run 30 nth = 30
loop 1: join 30 nth = 0
Exit ?
VmPeak: 248136 kB
VmSize: 35044 kB
VmHWM: 740 kB
VmRSS: 640 kB
VmStk: 136 kB
run 30 nth = 30
loop 2: join 30 nth = 0
Exit ?
.......
.......
loop 15: join 30 nth = 0
Exit ?
VmPeak: 248136 kB
VmSize: 35044 kB
VmHWM: 740 kB
VmRSS: 640 kB
VmStk: 136 kB
run 30 nth = 30
loop 16: join 30 nth = 0
Exit ?
VmPeak: 248136 kB
VmSize: 35044 kB
VmHWM: 740 kB
VmRSS: 640 kB
VmStk: 136 kB
run 30 nth = 30
loop 17: join 30 nth = 0
Exit ?
y
Bye
avp@avp-xub11:~/src/ig/tst$
Возможно проблема в FreeBsd.
Ответ 2
Странно, что никто не сказал про pthread_detach(). Помнится если его не запускать
память выделенная под поток не освобождается и очень шустро растет, что очень заметно
например в htop. Я вызываю эту штуку после pthread_create().
pthread_t restrict;
if(pthread_create(&restrict, ...)) return 0;
pthread_detach(restrict);
return 0;
"Функция pthread_join блокирует работу вызвавшей ее нити исполнения до завершения
thread'а с идентификатором thread." Не вижу никакой связи с использованием памяти.
Она тут не при чем.
Ответ 3
лимит комментов исчерпан.
@avp, -D_THREAD_SAFE не спас. Возможно, прийдется пересмотреть логику очищения, в
любом случае попробую и с detach для разнообразия, вдруг изменится чего. да, join
сейчас только 1 поток делает, когда получает признак через pipe(), как Вы мне когда-то
подсказали уже, за что большое спасибо :)