Changeset 152 for MicroThreading/UMicroThreading.pas
- Timestamp:
- Jan 27, 2011, 10:30:55 AM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
MicroThreading/UMicroThreading.pas
r151 r152 18 18 cthreads, 19 19 {$ENDIF}{$ENDIF} 20 Classes, SysUtils, Contnrs, SyncObjs, DateUtils, Dialogs, Forms, UPlatform;20 Classes, ExtCtrls, SysUtils, Contnrs, SyncObjs, DateUtils, Dialogs, Forms, UPlatform; 21 21 22 22 const … … 98 98 TMicroThreadThread = class(TThread) 99 99 Manager: TMicroThreadManager; 100 ExecuteTerminated: Boolean; 100 101 procedure Execute; override; 101 102 constructor Create(CreateSuspended: Boolean; … … 119 120 function Execute(Count: Integer): Integer; 120 121 public 122 Id: Integer; 121 123 procedure Yield; 122 124 constructor Create; … … 139 141 FLastId: Integer; 140 142 FFrequency: Int64; 141 F Terminated: Boolean;143 FMainThreadTerminated: Boolean; 142 144 FMicroThreads: TObjectList; // TList<TMicroThread> 143 145 FMainThreadManager: TMicroThreadManager; 144 146 FMicroThreadsLock: TCriticalSection; 145 147 FState: TMicroThreadSchedulerState; 148 FUseMainThread: Boolean; 149 FMainThreadStarter: TTimer; 146 150 function GetMicroThreadCount: Integer; 147 151 function GetThreadPoolCount: Integer; … … 150 154 procedure SetThreadPoolSize(const AValue: Integer); 151 155 function GetNextMicroThread: TMicroThread; 156 procedure ReleaseMicroThread(MicroThread: TMicroThread); 157 procedure SetUseMainThread(const AValue: Boolean); 152 158 procedure Start; 153 159 procedure Stop; 154 160 procedure PoolThreadTerminated(Sender: TObject); 155 161 procedure UpdateThreadPoolSize; 162 procedure MainThreadStart(Sender: TObject); 156 163 public 157 164 function Add(MicroThread: TMicroThread): Integer; … … 168 175 property MainThreadManager: TMicroThreadManager read FMainThreadManager; 169 176 property Active: Boolean read FActive write SetActive; 177 property UseMainThread: Boolean read FUseMainThread write SetUseMainThread; 170 178 end; 171 179 … … 222 230 223 231 procedure TMicroThreadManager.Yield; 224 var 225 I: Integer; 226 CurrentTime: TDateTime; 227 begin 228 CurrentTime := NowPrecise; 232 begin 229 233 if Assigned(FCurrentMicroThread) then begin 230 FCurrentMicroThread.FExecutionEndTime := CurrentTime;234 FCurrentMicroThread.FExecutionEndTime := NowPrecise; 231 235 FCurrentMicroThread.FExecutionTime := FCurrentMicroThread.FExecutionTime + 232 236 (FCurrentMicroThread.FExecutionEndTime - FCurrentMicroThread.FExecutionStartTime); 233 if FCurrentMicroThread.FState = tsRunning then234 FCurrentMicroThread.FState := tsWaiting;235 237 asm 236 238 // Store microthread stack … … 249 251 end; 250 252 FCurrentMicroThread.FManager := nil; 253 FScheduler.ReleaseMicroThread(FCurrentMicroThread); 251 254 FCurrentMicroThread := nil; 252 255 end; 253 256 254 FCurrentMicroThread := FScheduler.GetNextMicroThread; 255 256 if Assigned(FCurrentMicroThread) and (FExecutedCount < FExecuteCount) then begin 257 FCurrentMicroThread.FManager := Self; 258 Inc(FExecutedCount); 259 asm 260 // Store FScheduler stack 261 mov eax, Self 262 mov edx, esp 263 mov [eax].TMicroThreadManager.FStackPointer, edx 264 mov edx, ebp 265 mov [eax].TMicroThreadManager.FBasePointer, edx 266 end; 267 if not FCurrentMicroThread.FExecuted then begin 268 FCurrentMicroThread.FExecuted := True; 269 FCurrentMicroThread.FState := tsRunning; 270 FCurrentMicroThread.FExecutionStartTime := CurrentTime; 257 if FExecutedCount < FExecuteCount then begin 258 FCurrentMicroThread := FScheduler.GetNextMicroThread; 259 260 if Assigned(FCurrentMicroThread) then begin 261 Inc(FExecutedCount); 262 FCurrentMicroThread.FExecutionStartTime := NowPrecise; 263 FCurrentMicroThread.FManager := Self; 271 264 asm 272 // Restore microthread stack 273 mov ecx, Self 274 mov eax, [ecx].TMicroThreadManager.FCurrentMicroThread 275 mov edx, [eax].TMicroThread.FStackPointer 276 mov ecx, esp 277 mov esp, edx 278 push ebp // remember bp on micro thread stack for read back 279 push ecx 280 mov edx, [eax].TMicroThread.FBasePointer 281 mov ebp, edx 282 // We want to call virtual method Execute 283 // but virtual methods can be called only statically 284 // Then static method CallExecute is calling virtual method Execute 285 call TMicroThread.CallExecute 286 // end; 287 // StaticMicroThread.Execute; 288 // asm 289 pop edx 290 pop ebp 291 mov esp, edx 265 // Store FScheduler stack 266 mov eax, Self 267 mov edx, esp 268 mov [eax].TMicroThreadManager.FStackPointer, edx 269 mov edx, ebp 270 mov [eax].TMicroThreadManager.FBasePointer, edx 292 271 end; 293 //FSelected.Method(FSelected); 294 (* StaticManager := FCurrentMicroThread.FManager; 295 asm 296 // Restore FScheduler stack 297 mov eax, StaticManager // Self is invalid before BP restore 298 mov edx, [eax].TMicroThreadManager.FStackPointer 299 mov esp, edx 300 mov edx, [eax].TMicroThreadManager.FBasePointer 301 mov ebp, edx 302 end; 303 *) 304 FCurrentMicroThread.FManager := nil; 305 FCurrentMicroThread.FExecutionEndTime := CurrentTime; 306 FCurrentMicroThread.FExecutionTime := FCurrentMicroThread.FExecutionTime + 307 (FCurrentMicroThread.FExecutionEndTime - FCurrentMicroThread.FExecutionStartTime); 308 FCurrentMicroThread.FFinished := True; 309 if FCurrentMicroThread.FFreeOnTerminate then begin 310 // Microthread is finished, remove it from queue 311 with FScheduler do 312 try 313 FMicroThreadsLock.Acquire; 314 FMicroThreads.Delete(FMicroThreads.IndexOf(FCurrentMicroThread)); 315 finally 316 FMicroThreadsLock.Release; 272 if not FCurrentMicroThread.FExecuted then begin 273 FCurrentMicroThread.FExecuted := True; 274 asm 275 // Restore microthread stack 276 mov ecx, Self 277 mov eax, [ecx].TMicroThreadManager.FCurrentMicroThread 278 mov edx, [eax].TMicroThread.FStackPointer 279 mov esp, edx 280 mov edx, [eax].TMicroThread.FBasePointer 281 mov ebp, edx 282 // We want to call virtual method Execute 283 // but virtual methods can be called only statically 284 // Then static method CallExecute is calling virtual method Execute 285 call TMicroThread.CallExecute 286 287 // Restore FScheduler stack 288 // ecx register is set by CallExecute to running micro thread 289 mov eax, [ecx].TMicroThread.FManager 290 mov edx, [eax].TMicroThreadManager.FStackPointer 291 mov esp, edx 292 mov edx, [eax].TMicroThreadManager.FBasePointer 293 mov ebp, edx 294 end; 295 296 FCurrentMicroThread.FExecutionEndTime := NowPrecise; 297 FCurrentMicroThread.FExecutionTime := FCurrentMicroThread.FExecutionTime + 298 (FCurrentMicroThread.FExecutionEndTime - FCurrentMicroThread.FExecutionStartTime); 299 FCurrentMicroThread.FFinished := True; 300 if FCurrentMicroThread.FFreeOnTerminate then begin 301 // Microthread is finished, remove it from queue 302 with FScheduler do 303 try 304 FMicroThreadsLock.Acquire; 305 FMicroThreads.Delete(FMicroThreads.IndexOf(FCurrentMicroThread)); 306 finally 307 FMicroThreadsLock.Release; 308 end; 309 end else begin 310 FCurrentMicroThread.FManager := nil; 311 FScheduler.ReleaseMicroThread(FCurrentMicroThread); 312 end; 313 //FCurrentMicroThread.FManager := nil; 314 //FScheduler.ReleaseMicroThread(FCurrentMicroThread); 315 FCurrentMicroThread := nil; 316 end else 317 //if FCurrentMicroThread.State = tsWaiting then 318 begin 319 // Execute selected thread 320 asm 321 // Restore microthread stack 322 mov ecx, Self 323 mov eax, [ecx].TMicroThreadManager.FCurrentMicroThread 324 mov edx, [eax].TMicroThread.FStackPointer 325 mov esp, edx 326 mov edx, [eax].TMicroThread.FBasePointer 327 mov ebp, edx 317 328 end; 318 329 end; 319 FCurrentMicroThread := nil;320 end else321 if FCurrentMicroThread.State = tsWaiting then begin322 // Execute selected thread323 FCurrentMicroThread.FState := tsRunning;324 FCurrentMicroThread.FExecutionStartTime := CurrentTime;325 asm326 // Restore microthread stack327 mov ecx, Self328 mov eax, [ecx].TMicroThreadManager.FCurrentMicroThread329 mov edx, [eax].TMicroThread.FStackPointer330 mov esp, edx331 mov edx, [eax].TMicroThread.FBasePointer332 mov ebp, edx333 end;334 330 end; 335 end else begin336 FCurrentMicroThread := nil;337 331 end; 338 332 end; … … 370 364 begin 371 365 inherited; 366 ExecuteTerminated := False; 372 367 Manager := TMicroThreadManager.Create; 373 368 end; … … 375 370 destructor TMicroThreadThread.Destroy; 376 371 begin 372 Terminate; 373 repeat 374 Application.ProcessMessages; 375 Sleep(1); 376 until ExecuteTerminated; 377 377 378 Manager.Free; 378 379 inherited Destroy; … … 393 394 begin 394 395 Execute; 396 asm 397 mov ecx, Self 398 end; 395 399 end; 396 400 … … 513 517 constructor TMicroThreadScheduler.Create; 514 518 begin 515 FTerminated := True; 519 FMainThreadStarter := TTimer.Create(nil); 520 FMainThreadStarter.Enabled := False; 521 FMainThreadStarter.Interval := 1; 522 FMainThreadStarter.OnTimer := MainThreadStart; 523 FMainThreadTerminated := True; 516 524 FMicroThreadsLock := TCriticalSection.Create; 517 525 FMicroThreads := TObjectList.Create; … … 521 529 FMainThreadManager := TMicroThreadManager.Create; 522 530 FMainThreadManager.FScheduler := Self; 531 UseMainThread := False; 523 532 end; 524 533 … … 526 535 begin 527 536 Active := False; 537 FMainThreadStarter.Free; 528 538 FMainThreadManager.Free; 529 539 FThreadPool.Free; … … 534 544 535 545 procedure TMicroThreadScheduler.Start; 536 var 537 Executed: Integer; 538 I: Integer; 539 begin 540 FTerminated := False; 546 begin 547 FMainThreadTerminated := False; 541 548 UpdateThreadPoolSize; 542 549 FState := ssRunning; 543 repeat544 Executed := FMainThreadManager.Execute(10);545 Application.ProcessMessages;546 if Executed = 0 then Sleep(1);547 until FState <> ssRunning;548 FTerminated := True;549 550 end; 550 551 … … 567 568 Application.ProcessMessages; 568 569 Sleep(1); 569 until F Terminated and (ThreadPoolSize = 0);570 until FMainThreadTerminated and (ThreadPoolSize = 0); 570 571 FState := ssStopped; 571 572 end; 572 573 573 574 procedure TMicroThreadScheduler.PoolThreadTerminated(Sender: TObject); 574 begin 575 var 576 ThreadIndex: Integer; 577 begin 578 TMicroThreadThread(Sender).ExecuteTerminated := True; 575 579 try 576 580 FThreadPoolLock.Acquire; 577 581 FThreadPool.OwnsObjects := False; 578 FThreadPool.Delete(FThreadPool.IndexOf(Sender)); 582 ThreadIndex := FThreadPool.IndexOf(Sender); 583 if ThreadIndex <> -1 then FThreadPool.Delete(ThreadIndex); 579 584 FThreadPool.OwnsObjects := True; 580 585 finally … … 594 599 NewThread := TMicroThreadThread.Create(True); 595 600 NewThread.Manager.FScheduler := Self; 601 NewThread.Manager.Id := FThreadPool.Count; 596 602 NewThread.OnTerminate := PoolThreadTerminated; 597 603 ThreadPool.Add(NewThread); 598 604 NewThread.Resume; 599 605 end; 600 end else 601 ThreadPool.Count := FThreadPoolSize; 606 end else begin 607 while FThreadPool.Count > FThreadPoolSize do begin 608 FThreadPool.Delete(FThreadPool.Count - 1); 609 end; 610 end; 602 611 finally 603 612 FThreadPoolLock.Release; 604 613 end; 614 end; 615 616 procedure TMicroThreadScheduler.MainThreadStart(Sender: TObject); 617 var 618 Executed: Integer; 619 begin 620 FMainThreadStarter.Enabled := False; 621 repeat 622 Executed := FMainThreadManager.Execute(1); 623 Application.ProcessMessages; 624 if Executed = 0 then Sleep(1); 625 until (FState <> ssRunning) or (not FUseMainThread); 626 FMainThreadTerminated := True; 605 627 end; 606 628 … … 619 641 FRoundRobinIndex := 0; 620 642 while (I < FMicroThreads.Count) and 621 (TMicroThread(FMicroThreads[FRoundRobinIndex]). State <> tsWaiting) do begin643 (TMicroThread(FMicroThreads[FRoundRobinIndex]).FState <> tsWaiting) do begin 622 644 // WakeUp sleeping threads 623 645 if (TMicroThread(FMicroThreads[FRoundRobinIndex]).FState = tsSleeping) and … … 634 656 if I < FMicroThreads.Count then begin 635 657 Result := TMicroThread(FMicroThreads[FRoundRobinIndex]); 658 Result.FState := tsRunning; 636 659 end; 637 660 finally 638 661 FMicroThreadsLock.Release; 662 end; 663 end; 664 665 procedure TMicroThreadScheduler.ReleaseMicroThread(MicroThread: TMicroThread); 666 begin 667 try 668 FMicroThreadsLock.Acquire; 669 if MicroThread.FState = tsRunning then begin 670 MicroThread.FState := tsWaiting; 671 end; 672 finally 673 FMicroThreadsLock.Release; 674 end; 675 end; 676 677 procedure TMicroThreadScheduler.SetUseMainThread(const AValue: Boolean); 678 begin 679 if FUseMainThread = AValue then Exit; 680 FUseMainThread := AValue; 681 if FState = ssRunning then begin 682 if AValue then FMainThreadStarter.Enabled := True; 639 683 end; 640 684 end; … … 686 730 687 731 //StaticManagers := TObjectList.Create; 688 MainScheduler := TMicroThreadScheduler.Create;732 //MainScheduler := TMicroThreadScheduler.Create; 689 733 690 734 finalization 691 735 692 MainScheduler.Free;736 //MainScheduler.Free; 693 737 //StaticManagers.Free; 694 738
Note:
See TracChangeset
for help on using the changeset viewer.