[M3devel] sample program for testing threads / MUTEX

Olaf Wagner wagner at elegosoft.com
Mon Nov 9 11:26:27 CET 2009


Randy, could you add your new test(s) to the m3-sys/m3tests package?
That way they will automatically be included in regression testing.
Increasing the test coverage in this area would be great.

Thanks in advance,

Olaf

Quoting Randy Coleburn <rcoleburn at scires.com>:

> Some time ago we had a discussion about needing some tests for   
> threading and MUTEX.
>
> Jay Krell later referenced an online book titled "The Little Book of  
>  Semaphores".
>
> I've attached a program to this email that is a variation of the   
> problem presented in Section 8.1 of this book.
>
> You might try running it on various platforms to see if a problem is  
>  detected.
>
> The program takes 3 inputs:
>
> 1 = The number of Threads that should be created.
>
> 2 = The maximum count, i.e., the number of shared counter variables   
> to be created.
>
> 3 = Whether to use MUTEX protection for concurrency control.
>
> For example, on Windows Vista with the following inputs, I get the   
> results shown below:
>
> (1001, 1000000, 0) = FAIL (as expected), histogram = (0:32),   
> (1:999943), (2:25)
>
> (1001. 1000000, 1) = PASS (as expected), histogram = (1:1000000)
>
> Using these inputs, the program took nearly 3 minutes to run on a   
> recent vintage Dell laptop computer.
>
> Just because a particular test run succeeds doesn't mean all is   
> well.  Obviously, for small # of threads and/or small maxCount, even  
>  the non-MUTEX version will succeed sometimes.  But, trying larger   
> numbers will give a more robust test.
>
> If desired, I can try to implement some of the other test programs   
> in the book.  Let me know.
>
> Regards,
> Randy Coleburn
>
> MODULE ThreadTest1 EXPORTS Main;
>
> (* This program designed to test if MUTEX working properly using   
> multiple threads.
>    Author:  Randy Coleburn
>    Inspiration:  "The Little Book of Semaphores", by Allen Downey,   
> Section 8.1: Mutex checker problem.
>  *)
>
> IMPORT Fmt, IO, Thread, Time;
>
> <*FATAL IO.Error*>
>
> CONST
>    ModuleName = "ThreadTest1";
>    Delay = 0.11d0;
>
> TYPE
>    ChildClosure = Thread.Closure OBJECT
>       id: CARDINAL;
>    METHODS
>    OVERRIDES
>       apply := ChildApply;
>    END; (* ChildClosure *)
>
>    CounterArray = REF ARRAY OF CARDINAL;
>
> VAR
>    maxCount: CARDINAL := 0;
>    mutex: MUTEX := NEW(MUTEX);
>    numThreads: CARDINAL := 10;
>    sharedArray: CounterArray;
>    sharedCounter: CARDINAL := 0;
>    startTime: LONGREAL;
>    threadSafeMode: BOOLEAN := FALSE;
>
>
>
> PROCEDURE Print (msg: TEXT;
>                 )
>    RAISES {} =
> (* *)
> BEGIN (* Print *)
>    IO.Put(msg & "\n");
> END Print;
>
>
>
> PROCEDURE ChildApply (self: ChildClosure;
>                      ): REFANY
>    RAISES {} =
> (* *)
> CONST Proc = ModuleName & ".ChildApply";
> VAR
>    myID: TEXT := Proc & "( " & Fmt.Int(self.id) & " )";
>    numLoops: CARDINAL := 0;
> BEGIN (* ChildApply *)
>    Print("Begin " & myID);
>    IF threadSafeMode
>    THEN
>       WHILE sharedCounter < maxCount
>       DO
>          LOCK mutex DO
>             INC(sharedArray[sharedCounter]);
>             INC(sharedCounter);
>          END; (* lock *)
>          INC(numLoops);
>          Thread.Pause(Delay);
>       END; (* while *)
>    ELSE
>       WHILE sharedCounter < maxCount
>       DO
>          INC(sharedArray[sharedCounter]);
>          INC(sharedCounter);
>          INC(numLoops);
>          Thread.Pause(Delay);
>       END; (* while *)
>    END; (* if *)
>    Print("End " & myID & " ran " & Fmt.Int(numLoops) & " times.");
>    RETURN NIL;
> END ChildApply;
>
>
>
> PROCEDURE PrintHistogram ()
>    RAISES {} =
> (* *)
> CONST Proc = ModuleName & ".PrintHistogram";
> VAR
>    count: CounterArray;
>    error: BOOLEAN := FALSE;
> BEGIN (* PrintHistogram *)
>    Print("Begin" & Proc);
>    Print("(this make take a few moments when max count is large)\n");
>    count := NEW(CounterArray, maxCount+1);
>    FOR i := 0 TO maxCount
>    DO
>       count[i] := 0;
>    END; (* for *)
>    FOR i := 0 TO (maxCount - 1)
>    DO
>       WITH c = sharedArray[i]
>       DO
>          IF c > maxCount
>          THEN
>             error := TRUE;
>             Print("!!! Something really broken in CM3 because   
> sharedArray[" & Fmt.Int(i) & "] = " & Fmt.Int(c) & " which is   
> greater than maxCount !!!");
>          ELSE
>             INC(count[c]);
>          END; (* if *)
>       END; (* with *)
>    END; (* for *)
>    FOR n := 0 TO maxCount
>    DO
>       WITH total = count[n]
>       DO
>          IF total > 0
>          THEN
>             Print("(" & Fmt.Int(n) & ": " & Fmt.Int(total) & ")");
>          END; (* if *)
>          IF (n # 1) AND (total # 0)
>          THEN
>             error := TRUE;
>          ELSIF (n = 1) AND (total # maxCount)
>          THEN
>             error := TRUE;
>          END; (* if *)
>       END; (* with *)
>    END; (* for *)
>    IF error
>    THEN
>       Print("\n! ERROR DETECTED !");
>    ELSE
>       Print("\n! TEST PASSED !");
>    END; (* if *)
>    IF error AND threadSafeMode
>    THEN
>       Print("\n!!! Something is broken in the CM3 system and needs   
> to be fixed !!!");
>    ELSIF (NOT threadSafeMode)
>    THEN
>       IF error
>       THEN
>          Print("\nNote that errors are expected when not using   
> concurrency control.");
>       ELSE
>          Print("\nYou got lucky because the test should fail when   
> not using concurrency control.\nTry again with more threads and/or a  
>  greater max count.");
>       END; (* if *)
>    END; (* if *)
>    Print("\nEnd" & Proc);
> END PrintHistogram;
>
>
>
> VAR
>    answer: INTEGER;
> BEGIN (* ThreadTest1 *)
>      
> Print("-------------------------------------------------------------------------------");
>    Print("Module " & ModuleName);
>      
> Print("-------------------------------------------------------------------------------");
>    Print("This program designed to test if MUTEX working properly   
> using multiple threads.");
>    Print("Author:  Randy Coleburn");
>    Print("Inspiration:  \"The Little Book of Semaphores\", by Allen Downey");
>    Print("              Section 8.1: Mutex checker problem.");
>    Print("              http://www.greenteapress.com/semaphores/");
>      
> Print("-------------------------------------------------------------------------------\n");
>
>    REPEAT
>       IO.Put("Enter # of threads [0.." & Fmt.Int(LAST(CARDINAL)) & "]: ");
>       answer := IO.GetInt();
>    UNTIL answer >= 0;
>    numThreads := answer;
>
>    REPEAT
>       IO.Put("Enter max count [10.." & Fmt.Int(LAST(CARDINAL)-1) & "]: ");
>       answer := IO.GetInt();
>    UNTIL (answer >= 10) AND (answer < LAST(CARDINAL));
>    maxCount := answer;
>
>    REPEAT
>       IO.Put("Run in thread-safe mode [0=false, 1=true]: ");
>       answer := IO.GetInt();
>    UNTIL (answer = 0) OR (answer = 1);
>    threadSafeMode := (answer = 1);
>
>    sharedArray := NEW(CounterArray, maxCount);
>    FOR i := 0 TO (maxCount - 1)
>    DO
>       sharedArray[i] := 0;
>    END; (* for *)
>
>      
> Print("\n-------------------------------------------------------------------------------");
>    Print("Ready to start " & Fmt.Int(numThreads) & " threads   
> incrementing " & Fmt.Int(maxCount) & " shared counters");
>    IF threadSafeMode
>    THEN
>       Print("   using mutual exclusion semaphore for concurrency control.");
>       Print("   Expected Result = Test Passed with no errors.");
>    ELSE
>       Print("   without using any concurrency controls.");
>       Print("   Expected Result = Test Fails with errors.");
>    END; (* if *)
>    Print("Expected runtime = " & Fmt.Int(ROUND(FLOAT(maxCount,   
> LONGREAL) * Delay / FLOAT(numThreads, LONGREAL) / 60.0d0) + 1) & "   
> minutes.");
>      
> Print("-------------------------------------------------------------------------------");
>    Print("---Press ENTER to begin---");
>    EVAL IO.GetLine();
>    EVAL IO.GetLine();
>    startTime := Time.Now();
>
>    VAR child := NEW(REF ARRAY OF Thread.T, numThreads);
>    BEGIN (* block *)
>       FOR i := 1 TO numThreads
>       DO
>          child[i-1] := Thread.Fork(NEW(ChildClosure, id := i));
>       END; (* for *)
>       FOR i := 1 TO numThreads
>       DO
>          EVAL Thread.Join(child[i-1]);
>       END; (* for *)
>    END; (* block *)
>
>      
> Print("-------------------------------------------------------------------------------");
>    Print("All threads finished.  Run time = " &   
> Fmt.LongReal((Time.Now()-startTime)/60.0d0) & " minutes.");
>    Print("Result should be a total of " & Fmt.Int(maxCount) & "   
> ones.\nSee histogram below.\n");
>    PrintHistogram();
> END ThreadTest1.
>
>
> CONFIDENTIALITY NOTICE:  This email and any attachments are intended  
>  solely for the use of the named recipient(s). This e-mail may   
> contain confidential and/or proprietary information of Scientific   
> Research Corporation.  If you are not a named recipient, you are   
> prohibited from making any use of the information in the email and   
> attachments.  If you believe you have received this email in error,   
> please notify the sender immediately and permanently delete the   
> email, any attachments, and all copies thereof from any drives or   
> storage media and destroy any printouts of the email or attachments.
>
> EXPORT COMPLIANCE NOTICE:  This email and any attachments may   
> contain technical data subject to U.S export restrictions under the   
> International Traffic in Arms Regulations (ITAR) or the Export   
> Administration Regulations (EAR).  Export or transfer of this   
> technical data and/or related information to any foreign person(s)   
> or entity(ies), either within the U.S. or outside of the U.S., may   
> require export authorization by the appropriate U.S. Government   
> agency prior to export or transfer.  In addition, technical data may  
>  not be exported or transferred to certain countries or specified   
> designated nationals identified by U.S. embargo controls without   
> prior export authorization.  By accepting this email and any   
> attachments, all recipients confirm that they understand and will   
> comply with all applicable ITAR, EAR and embargo compliance   
> requirements.
>
>



-- 
Olaf Wagner -- elego Software Solutions GmbH
                Gustav-Meyer-Allee 25 / Gebäude 12, 13355 Berlin, Germany
phone: +49 30 23 45 86 96  mobile: +49 177 2345 869  fax: +49 30 23 45 86 95
    http://www.elegosoft.com | Geschäftsführer: Olaf Wagner | Sitz: Berlin
Handelregister: Amtsgericht Charlottenburg HRB 77719 | USt-IdNr: DE163214194




More information about the M3devel mailing list