Changeset 156 for MicroThreading/UMicroThreading.pas
- Timestamp:
- Jan 28, 2011, 2:12:42 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
MicroThreading/UMicroThreading.pas
r155 r156 28 28 TMicroThreadManager = class; 29 29 30 TMicroThreadState = (ts Waiting, tsRunning, tsBlocked, tsSuspended);30 TMicroThreadState = (tsNone, tsWaiting, tsRunning, tsBlocked, tsSuspended); 31 31 TMicroThreadBlockState = (tbsNone, tbsSleeping, tbsWaitFor, tbsTerminating, 32 32 tbsTerminated); … … 58 58 FExecutionEndTime: TDateTime; 59 59 FExecutionTime: TDateTime; 60 FExecutionCount: Integer; 60 61 FStack: Pointer; 61 62 FStackPointer: Pointer; … … 73 74 function GetStackUsed: Integer; 74 75 function GetTerminated: Boolean; 76 procedure SetManager(const AValue: TMicroThreadManager); 75 77 procedure SetScheduler(const AValue: TMicroThreadScheduler); 78 procedure CheckStack; 76 79 public 77 80 Name: string; … … 97 100 property BlockState: TMicroThreadBlockState read FBlockState; 98 101 property ExecutionTime: TDateTime read FExecutionTime; 102 property ExecutionCount: Integer read FExecutionCount; 99 103 property FreeOnTerminate: Boolean read FFreeOnTerminate 100 104 write FFreeOnTerminate; … … 102 106 property Scheduler: TMicroThreadScheduler read FScheduler 103 107 write SetScheduler; 104 property Manager: TMicroThreadManager read FManager ;108 property Manager: TMicroThreadManager read FManager write SetManager; 105 109 property StackUsed: Integer read GetStackUsed; 106 110 end; … … 140 144 FScheduler: TMicroThreadScheduler; 141 145 FThread: TMicroThreadThread; 146 FId: Integer; 147 procedure SetCurrentMicroThread(const AValue: TMicroThread); 142 148 function Execute(Count: Integer): Integer; 149 property CurrentMicroThread: TMicroThread read FCurrentMicroThread 150 write SetCurrentMicroThread; 143 151 public 144 Id: Integer;145 152 procedure Yield; 146 153 procedure Synchronize(AMethod: TThreadMethod); … … 148 155 destructor Destroy; override; 149 156 property Scheduler: TMicroThreadScheduler read FScheduler; 150 property CurrentMicroThread: TMicroThread read FCurrentMicroThread;151 157 end; 152 158 … … 176 182 procedure SetActive(const AValue: Boolean); 177 183 procedure SetThreadPoolSize(const AValue: Integer); 178 function GetNextMicroThread: TMicroThread;184 procedure GetNextMicroThread(Manager: TMicroThreadManager); 179 185 procedure ReleaseMicroThread(MicroThread: TMicroThread); 180 186 procedure SetUseMainThread(const AValue: Boolean); … … 206 212 207 213 const 208 MicroThreadStateText: array[TMicroThreadState] of string = (' Waiting',214 MicroThreadStateText: array[TMicroThreadState] of string = ('None', 'Waiting', 209 215 'Running', 'Blocked', 'Suspended'); 210 216 MicroThreadBlockStateText: array[TMicroThreadBlockState] of string = ('None', … … 214 220 procedure MTSleep(Duration: TDateTime); 215 221 function MTWaitForEvent(Event: TMicroThreadEvent; Duration: TDateTime): TWaitResult; 222 procedure Log(Text: string); 223 224 const 225 LogFileName: string = 'Log.txt'; 216 226 217 227 implementation … … 284 294 end; 285 295 296 var 297 LogLock: TCriticalSection; 298 299 procedure Log(Text: string); 300 var 301 LogFile: TextFile; 302 begin 303 try 304 LogLock.Acquire; 305 AssignFile(LogFile, LogFileName); 306 if FileExists(LogFileName) then Append(LogFile) 307 else Rewrite(LogFile); 308 WriteLn(LogFile, Text); 309 CloseFile(LogFile); 310 finally 311 LogLock.Release; 312 end; 313 end; 314 286 315 { TMicroThreadMethod } 287 316 … … 323 352 324 353 { TMicroThreadManager } 354 355 procedure TMicroThreadManager.SetCurrentMicroThread(const AValue: TMicroThread 356 ); 357 begin 358 if FCurrentMicroThread = AValue then Exit; 359 if Assigned(FCurrentMicroThread) then 360 FCurrentMicroThread.FManager := nil; 361 FCurrentMicroThread := AValue; 362 if Assigned(FCurrentMicroThread) then 363 FCurrentMicroThread.FManager := Self; 364 end; 325 365 326 366 function TMicroThreadManager.Execute(Count: Integer): Integer; … … 345 385 mov eax, [ecx].TMicroThreadManager.FCurrentMicroThread 346 386 mov edx, esp 387 mov ebx, ebp 347 388 mov [eax].TMicroThread.FStackPointer, edx 348 mov edx, ebp 349 mov [eax].TMicroThread.FBasePointer, edx 350 351 // Restore FScheduler stack 389 mov [eax].TMicroThread.FBasePointer, ebx 390 391 // Restore manager stack 352 392 mov edx, [ecx].TMicroThreadManager.FStackPointer 393 mov ebx, [ecx].TMicroThreadManager.FBasePointer 353 394 mov esp, edx 354 mov edx, [ecx].TMicroThreadManager.FBasePointer 355 mov ebp, edx 395 mov ebp, ebx 356 396 end; 357 FCurrentMicroThread.FManager := nil; 397 FCurrentMicroThread.CheckStack; 398 if FCurrentMicroThread = nil then 399 raise Exception.Create('x'); 358 400 FScheduler.ReleaseMicroThread(FCurrentMicroThread); 359 FCurrentMicroThread := nil;360 401 end; 361 402 362 403 if FExecutedCount < FExecuteCount then begin 363 FCurrentMicroThread := FScheduler.GetNextMicroThread; 364 404 FScheduler.GetNextMicroThread(Self); 365 405 if Assigned(FCurrentMicroThread) then begin 366 406 Inc(FExecutedCount); 367 407 FCurrentMicroThread.FExecutionStartTime := NowPrecise; 368 FCurrentMicroThread.FManager := Self;369 408 asm 370 // Store FScheduler stack409 // Store manager stack 371 410 mov eax, Self 372 411 mov edx, esp 412 mov ebx, ebp 373 413 mov [eax].TMicroThreadManager.FStackPointer, edx 374 mov edx, ebp 375 mov [eax].TMicroThreadManager.FBasePointer, edx 414 mov [eax].TMicroThreadManager.FBasePointer, ebx 376 415 end; 377 416 if not FCurrentMicroThread.FExecuted then begin 417 // First time micro thread execution 378 418 FCurrentMicroThread.FExecuted := True; 379 419 asm … … 382 422 mov eax, [ecx].TMicroThreadManager.FCurrentMicroThread 383 423 mov edx, [eax].TMicroThread.FStackPointer 424 mov ebx, [eax].TMicroThread.FBasePointer 384 425 mov esp, edx 385 mov edx, [eax].TMicroThread.FBasePointer 386 mov ebp, edx 426 mov ebp, ebx 387 427 // We want to call virtual method Execute 388 428 // but virtual methods can be called only statically … … 390 430 call TMicroThread.CallExecute 391 431 392 // Restore FScheduler stack432 // Restore manager stack 393 433 // ecx register is set by CallExecute to running micro thread 394 434 mov eax, [ecx].TMicroThread.FManager 395 435 mov edx, [eax].TMicroThreadManager.FStackPointer 436 mov ebx, [eax].TMicroThreadManager.FBasePointer 396 437 mov esp, edx 397 mov edx, [eax].TMicroThreadManager.FBasePointer 398 mov ebp, edx 438 mov ebp, ebx 399 439 end; 400 440 FCurrentMicroThread.CheckStack; 401 441 FCurrentMicroThread.FExecutionEndTime := NowPrecise; 402 442 FCurrentMicroThread.FExecutionTime := FCurrentMicroThread.FExecutionTime + 403 443 (FCurrentMicroThread.FExecutionEndTime - FCurrentMicroThread.FExecutionStartTime); 404 FCurrentMicroThread.FState := tsBlocked;444 FCurrentMicroThread.FStatePending := tsBlocked; 405 445 FCurrentMicroThread.FBlockState := tbsTerminated; 406 446 if FCurrentMicroThread.FFreeOnTerminate then begin … … 414 454 end; 415 455 end else begin 416 FCurrentMicroThread.FManager := nil;417 456 FScheduler.ReleaseMicroThread(FCurrentMicroThread); 418 457 end; 419 458 //FCurrentMicroThread.FManager := nil; 420 459 //FScheduler.ReleaseMicroThread(FCurrentMicroThread); 421 FCurrentMicroThread := nil;460 //FCurrentMicroThread := nil; 422 461 end else 423 //if FCurrentMicroThread.State = tsWaiting then424 462 begin 425 // Execute selected thread 463 // Regular selected microthread execution 464 FCurrentMicroThread.CheckStack; 426 465 asm 427 466 // Restore microthread stack … … 429 468 mov eax, [ecx].TMicroThreadManager.FCurrentMicroThread 430 469 mov edx, [eax].TMicroThread.FStackPointer 470 mov ebx, [eax].TMicroThread.FBasePointer 431 471 mov esp, edx 432 mov edx, [eax].TMicroThread.FBasePointer 433 mov ebp, edx 472 mov ebp, ebx 434 473 end; 435 474 end; … … 464 503 try 465 504 repeat 466 ExecutedCount := Manager.Execute(10 );505 ExecutedCount := Manager.Execute(100000); 467 506 if ExecutedCount = 0 then Sleep(1); 468 507 until Terminated; 469 508 except 470 on E: Exception do 509 on E: Exception do ; 471 510 //ExceptionHandler(E); 472 511 end; … … 485 524 Terminate; 486 525 repeat 487 Application.ProcessMessages;488 526 Sleep(1); 489 527 until ExecuteTerminated; … … 522 560 end; 523 561 562 procedure TMicroThread.SetManager(const AValue: TMicroThreadManager); 563 begin 564 if FManager = AValue then Exit; 565 if Assigned(FManager) then FManager.CurrentMicroThread := nil; 566 FManager := AValue; 567 if Assigned(FManager) then FManager.CurrentMicroThread := Self; 568 end; 569 524 570 procedure TMicroThread.SetScheduler(const AValue: TMicroThreadScheduler); 525 571 begin … … 527 573 end; 528 574 575 procedure TMicroThread.CheckStack; 576 begin 577 if not ((FStackPointer > FStack) and (FStackPointer < (FStack + FStackSize))) 578 then raise EStackOverflow.Create(Format('Microthread %d stack error', [FId])); 579 end; 580 529 581 procedure TMicroThread.Execute; 530 582 begin … … 534 586 procedure TMicroThread.Yield; 535 587 begin 588 if not Assigned(FManager) then 589 raise Exception.Create('Manager reference lost'); 590 FStatePending := tsWaiting; 536 591 FManager.Yield; 537 592 end; … … 582 637 FExecutionTime := 0; 583 638 FState := tsWaiting; 584 FStatePending := ts Waiting;639 FStatePending := tsNone; 585 640 if CreateSuspended then begin 586 641 FState := tsSuspended; 587 FStatePending := tsSuspended;588 642 end; 589 643 FFreeOnTerminate := True; … … 717 771 Application.ProcessMessages; 718 772 Sleep(1); 719 until FMainThreadTerminated and (ThreadPool Size= 0);773 until FMainThreadTerminated and (ThreadPoolCount = 0); 720 774 FState := ssStopped; 721 775 end; … … 730 784 FThreadPool.OwnsObjects := False; 731 785 ThreadIndex := FThreadPool.IndexOf(Sender); 732 if ThreadIndex <> -1 then FThreadPool.Delete(ThreadIndex); 786 if ThreadIndex = -1 then 787 raise Exception.Create('Trying to free thread not found in thread pool'); 788 FThreadPool.Delete(ThreadIndex); 789 finally 733 790 FThreadPool.OwnsObjects := True; 734 finally735 791 FThreadPoolLock.Release; 736 792 end; … … 748 804 NewThread := TMicroThreadThread.Create(True); 749 805 NewThread.Manager.FScheduler := Self; 750 NewThread.Manager. Id := FThreadPool.Count + 1;806 NewThread.Manager.FId := FThreadPool.Count + 1; 751 807 NewThread.Manager.FThread := NewThread; 752 808 NewThread.OnTerminate := PoolThreadTerminated; 809 NewThread.FreeOnTerminate := True; 753 810 ThreadPool.Add(NewThread); 754 811 NewThread.Resume; … … 778 835 end; 779 836 780 function TMicroThreadScheduler.GetNextMicroThread: TMicroThread;837 procedure TMicroThreadScheduler.GetNextMicroThread(Manager: TMicroThreadManager); 781 838 var 782 839 I: Integer; 783 840 CurrentTime: TDateTime; 784 begin 785 CurrentTime := NowPrecise; 786 Result := nil; 841 Selected: TMicroThread; 842 begin 787 843 try 788 844 FMicroThreadsLock.Acquire; 845 CurrentTime := NowPrecise; 789 846 I := 0; 847 Selected := nil; 790 848 Inc(FRoundRobinIndex); 791 849 if FRoundRobinIndex >= FMicroThreads.Count then … … 793 851 while (I < FMicroThreads.Count) do 794 852 with TMicroThread(FMicroThreads[FRoundRobinIndex]) do begin 795 FState := FStatePending;796 853 if (FState = tsWaiting) then Break 797 854 else … … 815 872 // Go to next thread 816 873 Inc(I); 817 Inc(FRoundRobinIndex); 818 if FRoundRobinIndex >= FMicroThreads.Count then 819 FRoundRobinIndex := 0; 874 FRoundRobinIndex := (FRoundRobinIndex + 1) mod FMicroThreads.Count; 820 875 end; 821 876 if I < FMicroThreads.Count then begin 822 Result := TMicroThread(FMicroThreads[FRoundRobinIndex]); 823 Result.FState := tsRunning; 824 Result.FStatePending := tsWaiting; 877 if Assigned(Manager.FCurrentMicroThread) then 878 raise Exception.Create('Manager have already have running microthread'); 879 Selected := TMicroThread(FMicroThreads[FRoundRobinIndex]); 880 Selected.FState := tsRunning; 881 Inc(Selected.FExecutionCount); 825 882 end; 883 Manager.CurrentMicroThread := Selected; 826 884 finally 827 885 FMicroThreadsLock.Release; … … 831 889 procedure TMicroThreadScheduler.ReleaseMicroThread(MicroThread: TMicroThread); 832 890 begin 891 if not Assigned(MicroThread) then 892 raise Exception.Create('Can''t realease nil thread.'); 833 893 try 834 894 FMicroThreadsLock.Acquire; 835 MicroThread.FState := MicroThread.FStatePending; 895 if MicroThread.FStatePending <> tsNone then begin 896 MicroThread.FState := MicroThread.FStatePending; 897 MicroThread.FStatePending := tsNone; 898 end; 899 MicroThread.Manager := nil; 836 900 finally 837 901 FMicroThreadsLock.Release; … … 893 957 initialization 894 958 959 DeleteFile(LogFileName); 960 LogLock := TCriticalSection.Create; 895 961 MainScheduler := TMicroThreadScheduler.Create; 896 962 … … 898 964 899 965 MainScheduler.Free; 966 LogLock.Free; 900 967 901 968 end.
Note:
See TracChangeset
for help on using the changeset viewer.