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]
Fibers - microsoft.com
Using Fibers - microsoft.com
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.
