Составители:
Рубрика:
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( #includeNULL, 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
- …
- следующая ›
- последняя »