Common Intermediate Language и системное программирование в Microsoft.Net. Макаров А.В - 120 стр.

UptoLike

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;
      }                                                                               }