Fiber 란? [Bottom] [Top]

A fiber is a unit of execution that must be manually scheduled by the application. Fibers run in the context of the threads that schedule them. Each thread can schedule multiple fibers. In general, fibers do not provide advantages over a well-designed multithreaded application. However, using fibers can make it easier to port applications that were designed to schedule their own threads.

From a system standpoint, a fiber assumes the identity of the thread that runs it. For example, if a fiber accesses thread local storage ( TLS ), it is accessing the thread local storage of the thread that is running it. In addition, if a fiber calls the ExitThread function, the thread that is running it exits. However, a fiber does not have all the same state information associated with it as that associated with a thread. The only state information maintained for a fiber is its stack, a subset of its registers, and the fiber data provided during fiber creation. The saved registers are the set of registers typically preserved across a function call.

Fibers are not preemptively scheduled. You schedule a fiber by switching to it from another fiber. The system still schedules threads to run. When a thread running fibers is preempted, its currently running fiber is preempted. The fiber runs when its thread runs.

Before scheduling the first fiber, call the ConvertThreadToFiber function to create an area in which to save fiber state information. The calling thread is now the currently executing fiber. The stored state information for this fiber includes the fiber data passed as an argument to ConvertThreadToFiber.

The CreateFiber function is used to create a new fiber from an existing fiber; the call requires the stack size, the starting address, and the fiber data. The starting address is typically a user-supplied function, called the fiber function, that takes one parameter (the fiber data) and does not return a value. If your fiber function returns, the thread running the fiber exits. To execute any fiber created with CreateFiber, call the SwitchToFiber function. You can call SwitchToFiber with the address of a fiber created by a different thread. To do this, you must have the address returned to the other thread when it called CreateFiber and you must use proper synchronization.

A fiber can retrieve the fiber data by calling the GetFiberData macro. A fiber can retrieve the fiber address at any time by calling the GetCurrentFiber macro.

A fiber can use fiber local storage ( FLS ) to create a unique copy of a variable for each fiber. If no fiber switching occurs, FLS acts exactly the same as thread local storage. The FLS functions ( FlsAlloc, FlsFree, FlsGetValue, and FlsSetValue ) manipulate the FLS associated with the current thread. If the thread is executing a fiber and the fiber is switched, the FLS is also switched.

To clean up the data associated with a fiber, call the DeleteFiber function. This data includes the stack, a subset of the registers, and the fiber data. If the currently running fiber calls DeleteFiber, its thread calls ExitThread and terminates. However, if a currently running fiber is deleted by another fiber, the thread running the deleted fiber is likely to terminate abnormally because the fiber stack has been freed.

참고링크 [Bottom] [Top]

Using Fibers [Bottom] [Top]

The CreateFiber function creates a new fiber for a thread. The creating thread must specify the starting address of the code that the new fiber is to execute. Typically, the starting address is the name of a user-supplied function. Multiple fibers can execute the same function.

The following example demonstrates how to create, schedule, and delete fibers. The fibers execute the locally defined functions ReadFiberFunc and WriteFiberFunc. This example implements a fiber-based file copy operation. When running the example, you must specify the source and destination files. Note that there are many other ways to copy file programmatically; this example exists primarily to illustrate the use of the fiber functions.

   1 #include <stdio.h>
   2 
   3 #define WIN32_LEAN_AND_MEAN
   4 
   5 #include <windows.h>
   6 
   7 
   8 // 상수 선언
   9 #define RTN_OK                                  (0)
  10 #define RTN_USAGE                               (1)
  11 #define RTN_ERROR                               (13)
  12 
  13 #define BUFFER_SIZE                             (32768)         // read/write buffer size
  14 #define FIBER_COUNT                             (3)             // max fibers (including primary)
  15 
  16 #define PRIMARY_FIBER                           (0)             // array index to primary fiber
  17 #define READ_FIBER                              (1)             // array index to read fiber
  18 #define WRITE_FIBER                             (2)             // array index to write fiber
  19 
  20 
  21 // 구조체 선언
  22 typedef struct
  23 {
  24         DWORD   dwParameter;                    // DWORD parameter to fiber (unused)
  25         DWORD   dwFiberResultCode;              // GetLastError() result code
  26         HANDLE  hFile;                          // handle to operate on
  27         DWORD   dwBytesProcessed;               // number of bytes processed
  28 } FIBERDATASTRUCT, *PFIBERDATASTRUCT, *LPFIBERDATASTRUCT;
  29 
  30 
  31 // 전역 변수 선언
  32 LPVOID  g_lpFiber[FIBER_COUNT];
  33 LPBYTE  g_lpBuffer;
  34 DWORD   g_dwBytesRead;
  35 
  36 
  37 // 함수 원형 선언
  38 VOID CALLBACK   ReadFiberFunc( PVOID lpParameter );
  39 VOID CALLBACK   WriteFiberFunc( PVOID lpParameter );
  40 void            DisplayFiberInfo();
  41 
  42 
  43 // Main() 함수 구현
  44 int __cdecl main( int argc, char *argv[] )
  45 {
  46         LPFIBERDATASTRUCT fs;
  47 
  48         if( 3 != argc )
  49         {
  50                 printf( "Usage: %s <SourceFile> <DestinationFile>\n", argv[0] );
  51                 return RTN_USAGE;
  52         }
  53 
  54         //
  55         // Allocate storage for our fiber data structures
  56         //
  57         fs = static_cast< LPFIBERDATASTRUCT >( HeapAlloc(
  58                 GetProcessHeap(),
  59                 0,
  60                 sizeof(FIBERDATASTRUCT) * FIBER_COUNT ) );
  61         if( NULL == fs )
  62         {
  63                 printf( "HeapAlloc error! (rc%=lu)\n", GetLastError() );
  64                 return RTN_ERROR;
  65         }
  66 
  67         //
  68         // Allocate storage for the read/write buffer
  69         //
  70         g_lpBuffer = static_cast< LPBYTE >( HeapAlloc(
  71                 GetProcessHeap(),
  72                 0,
  73                 BUFFER_SIZE ) );
  74         if( NULL == g_lpBuffer )
  75         {
  76                 printf( "HeapAlloc error! (rc=%lu)\n", GetLastError() );
  77                 return RTN_ERROR;
  78         }
  79 
  80         //
  81         // Open the source file
  82         //
  83         fs[READ_FIBER].hFile = CreateFile(
  84                 argv[1],
  85                 GENERIC_READ,
  86                 FILE_SHARE_READ,
  87                 NULL,
  88                 OPEN_EXISTING,
  89                 FILE_FLAG_SEQUENTIAL_SCAN,
  90                 NULL );
  91         if( INVALID_HANDLE_VALUE == fs[READ_FIBER].hFile )
  92         {
  93                 printf( "CreateFile error! (rc=%lu)\n", GetLastError() );
  94                 return RTN_ERROR;
  95         }
  96 
  97         //
  98         // Open the destination file
  99         //
 100         fs[WRITE_FIBER].hFile = CreateFile(
 101                 argv[2],
 102                 GENERIC_WRITE,
 103                 0,
 104                 NULL,
 105                 CREATE_NEW,
 106                 FILE_FLAG_SEQUENTIAL_SCAN,
 107                 NULL );
 108         if( INVALID_HANDLE_VALUE == fs[WRITE_FIBER].hFile )
 109         {
 110                 printf( "CreateFile error! (rc=%lu)\n", GetLastError() );
 111                 return RTN_ERROR;
 112         }
 113 
 114         //
 115         // Convert thread to a fiber, to allow scheduling other fibers
 116         //
 117         g_lpFiber[PRIMARY_FIBER] = ConvertThreadToFiber( &fs[PRIMARY_FIBER] );
 118         if( NULL == g_lpFiber[PRIMARY_FIBER] )
 119         {
 120                 printf( "ConvertThreadToFiber failed! rc=%lu\n", GetLastError() );
 121                 return RTN_ERROR;
 122         }
 123 
 124         //
 125         // Initialize the primary fiber data structure.  We don't use
 126         // the primary fiber data structure for anything in this sample.
 127         //
 128         fs[PRIMARY_FIBER].dwParameter           = 0;
 129         fs[PRIMARY_FIBER].dwFiberResultCode     = 0;
 130         fs[PRIMARY_FIBER].hFile                 = INVALID_HANDLE_VALUE;
 131 
 132         //
 133         // Create the Read fiber
 134         //
 135         g_lpFiber[READ_FIBER] = CreateFiber(
 136                 0,
 137                 ReadFiberFunc,
 138                 &fs[READ_FIBER] );
 139         if( NULL == g_lpFiber[READ_FIBER] )
 140         {
 141                 printf( "CreateFiber error! (rc=%lu)\n", GetLastError() );
 142                 return RTN_ERROR;
 143         }
 144 
 145         fs[READ_FIBER].dwParameter = 0x12345678;
 146 
 147         //
 148         // Create the Write fiber
 149         //
 150         g_lpFiber[WRITE_FIBER] = CreateFiber(
 151                 0,
 152                 WriteFiberFunc,
 153                 &fs[WRITE_FIBER] );
 154         if( NULL == g_lpFiber[WRITE_FIBER] )
 155         {
 156                 printf( "CreateFiber error! (rc=%lu)\n", GetLastError() );
 157                 return RTN_ERROR;
 158         }
 159 
 160         fs[WRITE_FIBER].dwParameter = 0x54545454;
 161 
 162         //
 163         // Switch to the read fiber
 164         //
 165         SwitchToFiber( g_lpFiber[READ_FIBER] );
 166 
 167         //
 168         // We have been scheduled again. Display results from the
 169         // read/write fibers
 170         //
 171         printf( "ReadFiber result == %lu Bytes Processed == %lu\n",
 172                 fs[READ_FIBER].dwFiberResultCode, fs[READ_FIBER].dwBytesProcessed );
 173 
 174         printf( "WriteFiber result == %lu Bytes Processed == %lu\n",
 175                 fs[WRITE_FIBER].dwFiberResultCode, fs[WRITE_FIBER].dwBytesProcessed );
 176 
 177         //
 178         // Delete the fibers
 179         //
 180         DeleteFiber( g_lpFiber[READ_FIBER] );
 181         DeleteFiber( g_lpFiber[WRITE_FIBER] );
 182 
 183         //
 184         // Close handles
 185         //
 186         CloseHandle( fs[READ_FIBER].hFile );
 187         CloseHandle( fs[WRITE_FIBER].hFile );
 188 
 189         //
 190         // Free allocated memory
 191         //
 192         HeapFree( GetProcessHeap(), 0, g_lpBuffer );
 193         HeapFree( GetProcessHeap(), 0, fs );
 194 
 195         return RTN_OK;
 196 }
 197 
 198 VOID CALLBACK ReadFiberFunc( PVOID lpParameter )
 199 {
 200         LPFIBERDATASTRUCT fds = static_cast< LPFIBERDATASTRUCT >( lpParameter );
 201 
 202         //
 203         // If this fiber was passed NULL for fiber data, just return,
 204         // causing the current thread to exit
 205         //
 206         if( NULL == fds )
 207         {
 208                 printf("Passed NULL fiber data.  Exiting current thread.\n");
 209                 return;
 210         }
 211 
 212         //
 213         // Display some information pertaining to the current fiber
 214         //
 215         DisplayFiberInfo();
 216 
 217         fds->dwBytesProcessed = 0;
 218 
 219         while( 1 )
 220         {
 221                 //
 222                 // Read data from file specified in the READ_FIBER structure
 223                 //
 224                 if( !ReadFile( fds->hFile, g_lpBuffer, BUFFER_SIZE,
 225                         &g_dwBytesRead, NULL ) )
 226                 {
 227                         break;
 228                 }
 229 
 230                 //
 231                 // if we reached EOF, break
 232                 //
 233                 if( 0 == g_dwBytesRead )
 234                         break;
 235 
 236                 //
 237                 // Update number of bytes processed in the fiber data structure
 238                 //
 239                 fds->dwBytesProcessed += g_dwBytesRead;
 240 
 241                 //
 242                 // Switch to the write fiber
 243                 //
 244                 SwitchToFiber( g_lpFiber[WRITE_FIBER] );
 245 
 246         } // while
 247 
 248         //
 249         // Update the fiber result code
 250         //
 251         fds->dwFiberResultCode = GetLastError();
 252 
 253         //
 254         // Switch back to the primary fiber
 255         //
 256         SwitchToFiber( g_lpFiber[PRIMARY_FIBER] );
 257 }
 258 
 259 VOID CALLBACK WriteFiberFunc( PVOID lpParameter )
 260 {
 261         LPFIBERDATASTRUCT fds = static_cast< LPFIBERDATASTRUCT >( lpParameter );
 262         DWORD dwBytesWritten;
 263 
 264         //
 265         // If this fiber was passed NULL for fiber data, just return,
 266         // causing the current thread to exit
 267         //
 268         if( NULL == fds )
 269         {
 270                 printf( "Passed NULL fiber data.  Exiting current thread.\n" );
 271                 return;
 272         }
 273 
 274         //
 275         // Display some information pertaining to the current fiber
 276         //
 277         DisplayFiberInfo();
 278 
 279         //
 280         // Assume all writes succeeded.  If a write fails, the fiber
 281         // result code will be updated to reflect the reason for failure
 282         //
 283         fds->dwBytesProcessed   = 0;
 284         fds->dwFiberResultCode  = ERROR_SUCCESS;
 285 
 286         while( 1 )
 287         {
 288                 //
 289                 // Write data to the file specified in the WRITE_FIBER structure
 290                 //
 291                 if( !WriteFile( fds->hFile, g_lpBuffer, g_dwBytesRead,
 292                         &dwBytesWritten, NULL ) )
 293                 {
 294                         //
 295                         // If an error occurred writing, break
 296                         //
 297                         break;
 298                 }
 299 
 300                 //
 301                 // Update number of bytes processed in the fiber data structure
 302                 //
 303                 fds->dwBytesProcessed += dwBytesWritten;
 304 
 305                 //
 306                 // Switch back to the read fiber
 307                 //
 308                 SwitchToFiber( g_lpFiber[READ_FIBER] );
 309 
 310         } // while
 311 
 312         //
 313         // If an error occurred, update the fiber result code...
 314         //
 315         fds->dwFiberResultCode = GetLastError();
 316 
 317         //
 318         // ...and switch to the primary fiber
 319         //
 320         SwitchToFiber( g_lpFiber[PRIMARY_FIBER] );
 321 }
 322 
 323 void DisplayFiberInfo()
 324 {
 325         LPFIBERDATASTRUCT fds   = static_cast< LPFIBERDATASTRUCT >( GetFiberData() );
 326         LPVOID lpCurrentFiber   = GetCurrentFiber();
 327 
 328         //
 329         // Determine which fiber is executing, based on the fiber address
 330         //
 331         if( lpCurrentFiber == g_lpFiber[READ_FIBER] )
 332                 printf( "Read Fiber entered" );
 333         else
 334         {
 335                 if ( lpCurrentFiber == g_lpFiber[WRITE_FIBER] )
 336                         printf( "Write Fiber entered" );
 337                 else
 338                 {
 339                         if( lpCurrentFiber == g_lpFiber[PRIMARY_FIBER] )
 340                                 printf( "Primary Fiber entered" );
 341                         else
 342                                 printf( "Unknown Fiber entered" );
 343                 }
 344         }
 345 
 346         //
 347         // Display dwParameter from the current fiber data structure
 348         //
 349         printf( " (dwParameter == 0x%lx)\n", fds->dwParameter );
 350 }

This example makes use of a fiber data structure which is used to determine the behavior and state of the fiber. One data structure exists for each fiber; the pointer to the data structure is passed to the fiber at fiber creation time using the parameter of the FiberProc function.

The calling thread calls the ConvertThreadToFiber function, which enables fibers to be scheduled by the caller. This also allows the fiber to be scheduled by another fiber. Next, the thread creates two additional fibers, one that performs read operations against a specified file, and another that performs the write operations against a specified file.

The primary fiber calls the SwitchToFiber function to schedule the read fiber. After a succesful read, the read fiber schedules the write fiber. After a succesful write in the write fiber, the write fiber schedules the read fiber. When the read/write cycle has completed, the primary fiber is scheduled, which results in the display of the read/write status. If an error occurs during the read or write operations, the primary fiber is scheduled and example displays the status of the operation.

Prior to process termination, the process frees the fibers using the DeleteFiber function, closes the file handles, and frees the allocated memory.


CategoryWin32

Fiber 프로그래밍 (last edited 2005-05-23 12:53:25 by 210)