>Чего-то я не вкурил.
>Имеется конструкция:
>
>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;
}