Составители:
Рубрика:
int main( void )
{
HANDLE hThread[ THREADS ];
unsigned dwThread;
dwTlsData = TlsAlloc();
/* создаем новые потоки */
for ( i = 0; i < THREADS; i++ )
hThread[i]=(HANDLE)_beginthreadex(
NULL, 0, ThreadProc, (void*)i, 0, &dwThread
);
/* дождаться завершения созданных потоков */
WaitForMultipleObjects( THREADS, hThread, TRUE, INFINITE );
for ( i = 0; i < THREADS; i++ ) CloseHandle( hThread[i] );
TlsFree( dwTlsData );
return 0;
}
В приведенном примере в функции main выделяется ячейка в ассоци-
ированном списке, индекс которой сохраняется в глобальной переменной
dwTlsData, после чего потоки могут сохранять в этой ячейке свои данные.
В Visual Studio работа с локальной для потока памятью может быть уп-
рощена при использовании _declspec(thread) при описании переменных.
В этом случае компилятор будет размещать эти переменные в специальном
сегменте данных (_TLS), который будет создаваться библиотекой времени
исполнения и ссылки на который будут разрешаться с использованием ас-
социированной с потоком памяти. Этот способ во многих случаях пред-
почтительнее явного управления локальной для потока памятью, так как
независимо от числа модулей, использующих такой сегмент, будет задейст-
вован только один указатель в ассоциированной памяти (построитель объ-
единит в один большой сегмент все _TLS сегменты модулей).
#include <process.h>
#include <windows.h>
#define THREADS 18
__declspec(thread) static int iptr[ 100 ];
void ProcA( int x )
{
int i;
for ( i = 0; i < 100; i++ ) iptr[i] = x;
}
Разработка параллельных приложений для ОС Windows
227
сом – они получат доступ к ячейкам своих собственных ассоциированных
массивов и не смогут узнать или изменить значения, сохраненные в этих
ячейках другими потоками. Для доступа к данным зарезервированной
ячейки используется функция TlsGetValue, возвращающая значение дан-
ной ячейки (в виде указателя, т.к. предполагается, что в ячейках хранятся
указатели на некоторые структуры данных) и функция TlsSetValue, изме-
няющая значение в соответствующей ячейке:
#include <process.h>
#include <windows.h>
#define THREADS 18
static DWORD dwTlsData;
void ProcA( int x )
{
int i;
int *iptr = (int*)TlsGetValue( dwTlsData );
for ( i = 0; i < 100; i++ ) iptr[i] = x;
}
int ProcB( void )
{
int i, x;
int *iptr = (int*)TlsGetValue( dwTlsData );
for ( i = x = 0; i < 100; i++ ) x += iptr[i];
return x;
}
unsigned __stdcall ThreadProc( void *param )
{
TlsSetValue( dwTlsData, (LPVOID)new int array[100] );
/* выделенные потоком данные размещены в общей куче,
используемой всеми потоками, однако указатель на
эти данные известен только потоку-создателю, так
как сохраняется в локальной для потока области */
ProcA( (int)param );
Sleep( 0 );
if ( ProcB() != 100*(int)param ) { /* ОШИБКА!!! */ }
delete[] (int*)TlsGetValue( dwTlsData );
return 0;
}
226
CIL и системное программирование в Microsoft .NET
226 CIL и системное программирование в Microsoft .NET Разработка параллельных приложений для ОС Windows 227
сом – они получат доступ к ячейкам своих собственных ассоциированных int main( void )
массивов и не смогут узнать или изменить значения, сохраненные в этих {
ячейках другими потоками. Для доступа к данным зарезервированной HANDLE hThread[ THREADS ];
ячейки используется функция TlsGetValue, возвращающая значение дан- unsigned dwThread;
ной ячейки (в виде указателя, т.к. предполагается, что в ячейках хранятся dwTlsData = TlsAlloc();
указатели на некоторые структуры данных) и функция TlsSetValue, изме- /* создаем новые потоки */
няющая значение в соответствующей ячейке: for ( i = 0; i < THREADS; i++ )
hThread[i]=(HANDLE)_beginthreadex(
#include NULL, 0, ThreadProc, (void*)i, 0, &dwThread
#include );
/* дождаться завершения созданных потоков */
#define THREADS 18 WaitForMultipleObjects( THREADS, hThread, TRUE, INFINITE );
static DWORD dwTlsData; for ( i = 0; i < THREADS; i++ ) CloseHandle( hThread[i] );
TlsFree( dwTlsData );
void ProcA( int x ) return 0;
{ }
int i; В приведенном примере в функции main выделяется ячейка в ассоци-
int *iptr = (int*)TlsGetValue( dwTlsData ); ированном списке, индекс которой сохраняется в глобальной переменной
for ( i = 0; i < 100; i++ ) iptr[i] = x; dwTlsData, после чего потоки могут сохранять в этой ячейке свои данные.
} В Visual Studio работа с локальной для потока памятью может быть уп-
рощена при использовании _declspec(thread) при описании переменных.
int ProcB( void ) В этом случае компилятор будет размещать эти переменные в специальном
{ сегменте данных (_TLS), который будет создаваться библиотекой времени
int i, x; исполнения и ссылки на который будут разрешаться с использованием ас-
int *iptr = (int*)TlsGetValue( dwTlsData ); социированной с потоком памяти. Этот способ во многих случаях пред-
for ( i = x = 0; i < 100; i++ ) x += iptr[i]; почтительнее явного управления локальной для потока памятью, так как
return x; независимо от числа модулей, использующих такой сегмент, будет задейст-
} вован только один указатель в ассоциированной памяти (построитель объ-
единит в один большой сегмент все _TLS сегменты модулей).
unsigned __stdcall ThreadProc( void *param )
{ #include
TlsSetValue( dwTlsData, (LPVOID)new int array[100] ); #include
/* выделенные потоком данные размещены в общей куче,
используемой всеми потоками, однако указатель на #define THREADS 18
эти данные известен только потоку-создателю, так __declspec(thread) static int iptr[ 100 ];
как сохраняется в локальной для потока области */
ProcA( (int)param ); void ProcA( int x )
Sleep( 0 ); {
if ( ProcB() != 100*(int)param ) { /* ОШИБКА!!! */ } int i;
delete[] (int*)TlsGetValue( dwTlsData );
return 0; for ( i = 0; i < 100; i++ ) iptr[i] = x;
} }
Страницы
- « первая
- ‹ предыдущая
- …
- 118
- 119
- 120
- 121
- 122
- …
- следующая ›
- последняя »
