UDP Speed Test Version 2.93 Now Available ! - TCP-IP

This is a discussion on UDP Speed Test Version 2.93 Now Available ! - TCP-IP ; "Chris Thomasson" wrote in message news:RMWdnYlPX9_6K3LbnZ2dnUVZ_ournZ2d@comcast.com. .. > "Skybuck Flying" wrote in message > news:fcoc5m$gbe$1@news6.zwoll1.ov.home.nl... >>> Why not do a producer/consumer where producer thread generates data and >>> consumer thread gathers it and presents it to GUI? >> >> The ...

+ Reply to Thread
Page 3 of 4 FirstFirst 1 2 3 4 LastLast
Results 41 to 60 of 69

Thread: UDP Speed Test Version 2.93 Now Available !

  1. Re: UDP Speed Test Version 2.93 Now Available !


    "Chris Thomasson" wrote in message
    news:RMWdnYlPX9_6K3LbnZ2dnUVZ_ournZ2d@comcast.com. ..
    > "Skybuck Flying" wrote in message
    > news:fcoc5m$gbe$1@news6.zwoll1.ov.home.nl...
    >>> Why not do a producer/consumer where producer thread generates data and
    >>> consumer thread gathers it and presents it to GUI?

    >>
    >> The data needs only to be displayed once per second.

    >
    > Then the consumer would just display once per-second? Why not? It could
    > dequeue a thousand messages and only display them once per-second, no?


    This is how it works:

    A Windows Timer is set to fire every second.

    The GUI receives this timer message.

    "This is the consumer"

    Ofcourse the consumer can not block on some queue, that would freeze the
    gui.

    Bye,
    Skybuck.



  2. Re: UDP Speed Test Version 2.93 Now Available !

    A thread does:

    while running do
    begin
    lock
    some code
    some code
    unlock
    end;

    So it's almost always locked... by not really so it's not a flaw.

    Let's continue this discussion from the slightly less simple example I gave
    in another sub thread.

    I am interested in seeing if you have any alternative to replace the
    critical section.

    Bye,
    Skybuck.



  3. Re: UDP Speed Test Version 2.93 Now Available !

    Also if you do have some alternative, some pseudo code would be just fine to
    help me understand your method.

    Then later we could discuss actual code.

    Bye,
    Skybuck.



  4. Re: UDP Speed Test Version 2.93 Now Available !

    "Skybuck Flying" wrote in message
    news:fcpdr9$lao$1@news3.zwoll1.ov.home.nl...
    >
    > "Chris Thomasson" wrote in message
    > news:RMWdnYlPX9_6K3LbnZ2dnUVZ_ournZ2d@comcast.com. ..
    >> "Skybuck Flying" wrote in message
    >> news:fcoc5m$gbe$1@news6.zwoll1.ov.home.nl...
    >>>> Why not do a producer/consumer where producer thread generates data and
    >>>> consumer thread gathers it and presents it to GUI?
    >>>
    >>> The data needs only to be displayed once per second.

    >>
    >> Then the consumer would just display once per-second? Why not? It could
    >> dequeue a thousand messages and only display them once per-second, no?

    >
    > This is how it works:
    >
    > A Windows Timer is set to fire every second.
    >
    > The GUI receives this timer message.
    >
    > "This is the consumer"
    >
    > Ofcourse the consumer can not block on some queue, that would freeze the
    > gui.


    You can do it with GUI like this:

    static queue g_q;

    consumer {
    message* msg = 0;
    for(; {
    WaitForGUIEvent(GUI, 1000); /* wait 100 milliseconds for event */
    msg = queue_pop_try(&g_q); /* non-blocking */
    if (msg) {
    message_process(msg);
    }
    }
    }

    producer() {
    message* msg = 0;
    for(; {
    /* wait for the need to create data */
    msg = /* acquire/init a message object */
    if (msg) {
    queue_push(&g_q, msg);
    }
    }
    }




    We don't need a GUI. I want to do a simple Console application that creates
    two threads and two single-producer/consumer queues for bi-directional
    communication. Something like very simple like this:


    struct thread {
    spsc_queue sendq;
    spsc_queue recvq;
    };


    thread_entry(thread *_this, thread *other) {
    message* msg = /* acquire new message */
    spsc_queue_push(&other->sendq);
    for(; {
    msg = spsc_queue_pop(&_this->recvq); /* blocks on empty */
    message_process(msg);
    spsc_queue_push(&other->sendq);
    }
    }


    int main() {
    thread worker_1, worker_2;
    handle t1 = thread_start(thread_entry, &worker_1, &worker_2);
    handle t2 = thread_start(thread_entry, &worker_2, &worker_1);
    thread_join(t2);
    thread_join(t1);
    return 0;
    }


    We can see if a CRITICAL_SECTION based single producer/consumer queue can
    beat a lock-free one. Please note that a lock-free queue of this nature does
    not any interlocked instructions or any expensive #StoreLoad or #LoadStore
    style memory barriers.


  5. Re: UDP Speed Test Version 2.93 Now Available !

    "Skybuck Flying" wrote in message
    news:fcpdan$i2v$1@news3.zwoll1.ov.home.nl...
    > Irrelevant example, it's too simple.
    >
    > What I ment is a slightly less simple example:
    >
    > Here is a better example:
    >
    > CriticalSection.Enter;
    >
    > A := A + 1;
    > B := B + 1;
    > C := C + A;
    > D := D + B;
    > E := E + 5;
    > F := F + 7;
    >
    > CriticalSection.Leave;
    >
    > What you described is now useless.
    >
    > All the "counters" must remain synchronized.
    >
    > What is your alternative for the critical section ?


    My first piece of advise is to keep your locked regions of code very small.
    You don't want to do complex calculations or anything that may block inside
    of them. As for lock-free, well it is simply not applicable to all
    situations. However, here is a ad-hoc lock-free answer to your question:

    union count64 {
    __int8 a;
    __int8 b;
    __int8 c;
    __int8 d;
    __int8 e;
    __int8 f;
    __int8 g;
    __int8 h;
    __int64 whole;
    };


    __int64 count64_inc(union count64 volatile* _this) {
    count64 swap, cmp;
    do {
    cmp.whole = _this->whole;
    swap.a = cmp.a + 1;
    swap.b = cmp.b + 1;
    swap.c = cmp.c + swap.a;
    swap.d = cmp.d + swap.b;
    swap.e = cmp.e + 5;
    swap.f = cmp.f + 7;
    swap.g = cmp.g + swap.d;
    swap.h = cmp.h + 1;
    } while (! CAS64(&_this->whole, cmp.whole, swap.whole));
    return swap.whole;
    }



    You are generally limited to working within memory sizes that are directly
    *CAS'able.; the memory also need to be properly aligned. In this case we can
    use 64-bit CAS.



    _______
    * - CAS stand for Compare-And-Swap


  6. Re: UDP Speed Test Version 2.93 Now Available !

    I don't quite understand how your example works but here's what I understand
    from it:

    First of all your method/idea is to not block any code.

    Your idea is to use temporarely or alternative storage.

    Each thread then copies/reads values from one of the storages and update
    another storage.

    What does CAS do ?

    And why do you call it compare and swap ?

    Also why is the loop needed ?

    What's the idea behind it ?

    Bye,
    Skybuck.



  7. Re: UDP Speed Test Version 2.93 Now Available !

    First of all I do need a GUI.

    Second of all the GUI must be updated in the main thread for Delphi
    applications otherwise strange things could happen.

    If you do want to have a seperate thread to update some gui then the
    synchronize method must be used.

    Also how is the wait for gui thing suppose to work ?

    Maybe you should try bringing your ideas into practice with a Delphi GUI
    application

    Furthermore I do not believe that simply creating more threads gives any
    performance improvements at all.

    Using more threads simply means using more context switches which means more
    cpu processing power wasted.

    Maybe the application would get more processing time from the operating
    system because it has more threads but that's cheating.

    Bye,
    Skybuck.



  8. Re: UDP Speed Test Version 2.93 Now Available !

    Ok, I read up on lock free algorithm and cas and it's now clear to me what
    CAS does.

    It's still not clear to me how your example works.

    I shall read some more about wait free algorithms.

    Bye,
    Skybuck.



  9. Re: UDP Speed Test Version 2.93 Now Available !

    Ok,

    I shall try an attempt to explain your code:

    Maybe whole means all the other variables.

    __int64 count64_inc(union count64 volatile* _this)
    {
    count64 swap; // additional storage
    count64 cmp; // additional storage
    do {
    cmp.whole = _this->whole; // compare storage is overwritten with
    parameter

    // new/swap storage is calculated based on old compare storage.
    swap.a = cmp.a + 1;
    swap.b = cmp.b + 1;
    swap.c = cmp.c + swap.a;
    swap.d = cmp.d + swap.b;
    swap.e = cmp.e + 5;
    swap.f = cmp.f + 7;
    swap.g = cmp.g + swap.d;
    swap.h = cmp.h + 1;

    // cas is performend on the parameter, with the old value, and new value
    // if cas fails then the above code is repeated over and over and over
    and over until it succeeds.
    } while (! CAS64(&_this->whole, cmp.whole, swap.whole));
    return swap.whole; // finally if it succeeds the new values are returned.
    }

    I shall try this idea in Delphi and see what happens

    Ofcourse as already mentioned on wikipedia which I read... this might always
    fail if something else is always updating it.

    Bye,
    Skybuck.



  10. Re: UDP Speed Test Version 2.93 Now Available !

    Also maybe the union is not necessary.

    I shall try and work out an idea:

    The data producer simply modifies it's variables.

    Then once it's done it copies the variables to some external/shared storage.

    This has some drawbacks:

    The copy takes time, extra external/shared storage necessary.

    However it could have some adventages.

    For example:

    The data producer only tries to copy it once.

    If it fails it doesn't try again and simply continues, since the data is not
    that important... newer values are ok too.

    The consumer also makes his own copy of this shared data.

    So two copies occur... one from the producer, and one from the consumer.

    The idea is to minimize the sections of code that need to be locked.

    The shared memory is a way to quickly exchange data... without having to
    wait on more expensive routines like string displays or conversions...
    and gui update codes.

    So idea is to:

    Freely read/write data in data producer.

    Freely read data in data consumer.

    Only the copieing of data from producer to shared memory or from shared
    memory to consumer is locked.

    And it's locked in such a way that the producer can simply continue if the
    consumer has it locked.

    So far this would only work for a read only consumer.

    Suppose consumer needs to alter data.... then it needs to copy back the data
    to the shared memory.

    Suppose the data producer meanwhile altered it's copy then ofcourse a race
    condition has occured.

    If both threads needs to alter data then a thread might have to throw away
    his calculations and start over with the newly updated memory.

    Might be interesting..

    I'll give it a try and see what happens.

    Me wonders though... if copieing would be faster than waiting for a critical
    section.

    Bye,
    Skybuck.



  11. Re: UDP Speed Test Version 2.93 Now Available !

    Hi,

    I have created a little test/benchmark program, to compare these "CAS"
    locking/unlocking ideas against critical sections.

    I suspect Windows probably uses CAS for critical sections so this test might
    be really dumb expect there are some differences in the way it's used, the
    first technique uses copies+cas, the second technique simply uses shared
    data+critical sections.

    So the way the locking is used is different, so maybe not so dumb after all:

    One conclusion can be drawn:

    The critical section method is of higher quality, the screen gets updated on
    a more regular basis.

    Performance-wise it's inconclusive, maybe if the producers did more complex
    calculations differences might start showing.

    // *** Begin of Code ***

    program Project1;

    {$APPTYPE CONSOLE}

    {

    Test Lock Free Idea's

    Version 0.01 created on 19 september 2007 by Skybuck Flying

    Investigate idea to write non locking or lock free code

    Idea is to copy data, modify one copy, while the others remain stable.

    The stable copies or used by those that needed synchronized data.

    This simple benchmark compares my own Locking/Unlocking Techniques against
    CriticalSections.

    I am not yet sure if the locking/unlocking techniques work perfeclty.

    So far I can see one problem: Delphi strings which are copy-on-write which
    might give problems for
    locking/unlocking code/data copies.

    This is where critical section might be safer.

    Benchmark conclusion:

    More or less inconclusive, code performs more or less the same, the critical
    sections probably slightly
    faster because of less code overhead.

    Maybe if the data producer did more complex calculations it might become an
    interesting technique.

    However when thing can clearly be seen if the comments are uncommented.

    The locking/unlocking mechanism is of less quality because the try lock
    might fail and then nothing
    will be updated to the screen !

    }

    {$RangeChecks OFF}
    {$OverflowChecks Off}

    uses
    SysUtils, Classes, Windows, SyncObjs;

    // Skybuck's Atomic TryLock Algorithm/Method:
    function TryLock( var ParaLock : LongBool ) : LongBool;
    begin
    result := not LongBool( InterlockedCompareExchange( Integer(ParaLock),
    Integer(LongBool(True)), Integer(LongBool(False)) ) );
    end;

    // Skybuck's Atomic TryUnLock Algorithm/Method:
    function TryUnlock( var ParaLock : LongBool ) : LongBool;
    begin
    result := LongBool( InterlockedCompareExchange( Integer(ParaLock),
    Integer(LongBool(False)), Integer(LongBool(True)) ) );
    end;

    type
    TsharedData = record
    mCriticalSection : TcriticalSection; // for critical producer/consumer
    mLocked : LongBool;
    mA : integer;
    mB : integer;
    mC : double;
    mD : string;
    mF : byte;
    mG : word;
    mRuns : int64;
    end;

    TProducer = class(Tthread)
    private

    protected
    procedure Execute; override;

    public

    end;

    TConsumer = class(Tthread)
    private

    protected
    procedure Execute; override;

    public

    end;

    TCriticalProducer = class(Tthread)
    private

    protected
    procedure Execute; override;

    public

    end;

    TCriticalConsumer = class(Tthread)
    private

    protected
    procedure Execute; override;

    public

    end;

    var
    mProducerCopy : TsharedData;
    mConsumerCopy : TsharedData;
    mSharedCopy : TsharedData;

    procedure TProducer.Execute;
    begin
    while not Terminated do
    begin
    with mProducerCopy do
    begin
    // lock our memory.
    if TryLock( mLocked ) then
    begin
    mA := mA + 1;
    mB := mB + 2;
    mC := mC + 3;
    mD := 'Hello: ' + IntToStr(mA);
    mF := mF + 4;
    mG := mG + 5;
    mRuns := mRuns + 1;

    // now try locking the memory of the others which should be updated with
    our data
    // if the lock fails, to bad, do no update, and simply continue with our
    own data.

    if TryLock( mConsumerCopy.mLocked ) then
    begin
    mConsumerCopy.mA := mA;
    mConsumerCopy.mB := mB;
    mConsumerCopy.mC := mC;
    mConsumerCopy.mD := mD; // could be a problem, since it's reference
    counted, we must force a copy somehow
    mConsumerCopy.mF := mF;
    mConsumerCopy.mG := mG;

    TryUnLock( mConsumerCopy.mLocked );
    end;

    TryUnLock( mLocked ); // should always succeed me thinks
    end; // else do nothing
    end;
    end;
    end;

    procedure TConsumer.Execute;
    begin
    while not Terminated do
    begin
    // Sleep( 1000 );

    with mConsumerCopy do
    begin
    // try to lock our memory
    if TryLock( mLocked ) then
    begin

    mA := mA + 1;
    mA := mB;
    mC := mC + 3;
    (*

    writeln('Lockedxx:');
    writeln( mA );
    writeln( mB );
    writeln( mC );
    writeln( mD );
    writeln( mF );
    writeln( mG );
    *)

    // unlock it
    TryUnLock( mLocked );
    end;
    end;
    end;
    end;

    procedure TCriticalProducer.Execute;
    begin
    while not Terminated do
    begin
    with mSharedCopy do
    begin
    mCriticalSection.Enter;

    mA := mA + 1;
    mB := mB + 2;
    mC := mC + 3;
    mD := 'Hello: ' + IntToStr(mA);
    mF := mF + 4;
    mG := mG + 5;
    mRuns := mRuns + 1;

    mCriticalSection.Leave;
    end;
    end;
    end;

    procedure TCriticalConsumer.Execute;
    begin
    while not Terminated do
    begin
    with mSharedCopy do
    begin
    // Sleep( 1000 );

    mCriticalSection.Enter;

    // Let's do something crazy instead to full test it

    mA := mA + 1;
    mA := mB;
    mC := mC + 3;

    (*

    writeln('Critical:');



    writeln( mA );
    writeln( mB );
    writeln( mC );
    writeln( mD );
    writeln( mF );
    writeln( mG );
    *)

    mCriticalSection.Leave;
    end;
    end;
    end;

    procedure ClearCopy( ParaCopy : TSharedData );
    begin
    with ParaCopy do
    begin
    mLocked := false;
    mA := 0;
    mB := 0;
    mC := 0;
    Pointer(mD) := nil;
    mF := 0;
    mG := 0;
    end;
    end;

    procedure Main;
    var
    mProducer : TProducer;
    mConsumer : TConsumer;

    mCriticalProducer : TCriticalProducer;
    mCriticalConsumer : TCriticalConsumer;

    begin
    writeln('program started');

    ClearCopy( mProducerCopy );
    ClearCopy( mConsumerCopy );
    ClearCopy( mSharedCopy );

    mSharedCopy.mCriticalSection := TCriticalSection.Create;

    // perform locked test
    mProducer := TProducer.Create(True);
    mProducer.FreeOnTerminate := false;

    mConsumer := TConsumer.Create(True);
    mConsumer.FreeOnTerminate := false;

    // wait 1 second so program can be loaded
    Sleep( 1000 );

    mProducer.Resume;
    mConsumer.Resume;

    sleep(10000);

    mConsumer.Terminate;
    mProducer.Terminate;

    mConsumer.WaitFor;
    mConsumer.Free;

    mProducer.WaitFor;
    mProducer.Free;

    // perform critical test

    mCriticalProducer := TCriticalProducer.Create(True);
    mCriticalProducer.FreeOnTerminate := false;

    mCriticalConsumer := TCriticalConsumer.Create(True);
    mCriticalConsumer.FreeOnTerminate := false;

    // wait 1 second so program can be loaded
    Sleep( 1000 );

    mCriticalProducer.Resume;
    mCriticalConsumer.Resume;

    sleep(10000);

    mCriticalConsumer.Terminate;
    mCriticalProducer.Terminate;

    mCriticalConsumer.WaitFor;
    mCriticalConsumer.Free;

    mCriticalProducer.WaitFor;
    mCriticalProducer.Free;

    mSharedCopy.mCriticalSection.Free;

    WriteLn('Locked Producer Runs : ', mProducerCopy.mRuns );
    WriteLn('Critical Producer Runs: ', mSharedCopy.mRuns );

    writeln('press enter to exit');
    readln;

    writeln('program finished');
    end;

    begin
    try
    Main;
    except
    on E:Exception do
    Writeln(E.Classname, ': ', E.Message);
    end;
    end.

    // *** End of Code ***

    Enjoy

    Bye,
    Skybuck =D



  12. Re: UDP Speed Test Version 2.93 Now Available !

    Yup the TryLock method I wrote is probably the same as
    TCriticalSection.TryEnter

    Here is the same program slightly modified to use TryEnter instead

    // *** Begin of Code ***

    program Project1;

    {$APPTYPE CONSOLE}

    {

    Test Lock Free Idea's

    Version 0.01 created on 19 september 2007 by Skybuck Flying

    Investigate idea to write non locking or lock free code

    Idea is to copy data, modify one copy, while the others remain stable.

    The stable copies are used by those that needed synchronized data.

    This simple benchmark compares my own Locking/Unlocking Techniques against
    CriticalSections.

    I am not yet sure if the locking/unlocking techniques work perfeclty.

    So far I can see one problem: Delphi strings which are copy-on-write which
    might give problems for
    locking/unlocking code/data copies.

    This is where critical section might be safer.

    Benchmark conclusion:

    More or less inconclusive, code performs more or less the same, the critical
    sections probably slightly
    faster because of less code overhead.

    Maybe if the data producer did more complex calculations it might become an
    interesting technique.

    However one thing can clearly be seen if the comments are uncommented.

    The locking/unlocking mechanism is of less quality because the try lock
    might fail and then nothing
    will be updated to the screen !

    }

    {

    Version 0.02 created on 19 september 2007 by Skybuck Flying

    Apperently Delphi 2007 has a new member for TCriticalSection which is not
    that well documented...

    It's probably actually the same as "my" TryLock method lol

    To prove this the code will be replaced with that method to see if it works
    the same

    Yup it works.

    }


    {$RangeChecks OFF}
    {$OverflowChecks Off}

    uses
    SysUtils,
    Classes,
    Windows,
    SyncObjs;

    // Skybuck's Atomic TryLock Algorithm/Method:
    // disabled
    {

    function TryLock( var ParaLock : LongBool ) : LongBool;
    begin
    result := not LongBool( InterlockedCompareExchange( Integer(ParaLock),
    Integer(LongBool(True)), Integer(LongBool(False)) ) );
    end;

    // Skybuck's Atomic TryUnLock Algorithm/Method:
    function TryUnlock( var ParaLock : LongBool ) : LongBool;
    begin
    result := LongBool( InterlockedCompareExchange( Integer(ParaLock),
    Integer(LongBool(False)), Integer(LongBool(True)) ) );
    end;
    }

    type
    TsharedData = record
    mCriticalSection : TcriticalSection; // for critical producer/consumer
    mLocked : LongBool;
    mA : integer;
    mB : integer;
    mC : double;
    mD : string;
    mF : byte;
    mG : word;
    mRuns : int64;
    end;

    TProducer = class(Tthread)
    private

    protected
    procedure Execute; override;

    public

    end;

    TConsumer = class(Tthread)
    private

    protected
    procedure Execute; override;

    public

    end;

    TCriticalProducer = class(Tthread)
    private

    protected
    procedure Execute; override;

    public

    end;

    TCriticalConsumer = class(Tthread)
    private

    protected
    procedure Execute; override;

    public

    end;

    var
    mProducerCopy : TsharedData;
    mConsumerCopy : TsharedData;
    mSharedCopy : TsharedData;

    procedure TProducer.Execute;
    begin
    while not Terminated do
    begin
    with mProducerCopy do
    begin
    // lock our memory.
    // if TryLock( mLocked ) then

    if mCriticalSection.TryEnter then
    begin
    mA := mA + 1;
    mB := mB + 2;
    mC := mC + 3;
    mD := 'Hello: ' + IntToStr(mA);
    mF := mF + 4;
    mG := mG + 5;
    mRuns := mRuns + 1;

    // now try locking the memory of the others which should be updated with
    our data
    // if the lock fails, to bad, do no update, and simply continue with our
    own data.

    if mConsumerCopy.mCriticalSection.TryEnter then
    begin
    mConsumerCopy.mA := mA;
    mConsumerCopy.mB := mB;
    mConsumerCopy.mC := mC;
    mConsumerCopy.mD := mD; // could be a problem, since it's reference
    counted, we must force a copy somehow
    mConsumerCopy.mF := mF;
    mConsumerCopy.mG := mG;

    mConsumerCopy.mCriticalSection.Leave;
    end;

    mCriticalSection.Leave;
    end; // else do nothing
    end;
    end;
    end;

    procedure TConsumer.Execute;
    begin
    while not Terminated do
    begin
    // Sleep( 1000 );

    with mConsumerCopy do
    begin
    // try to lock our memory
    if mCriticalSection.TryEnter then
    begin

    mA := mA + 1;
    mA := mB;
    mC := mC + 3;
    (*

    writeln('Lockedxx:');
    writeln( mA );
    writeln( mB );
    writeln( mC );
    writeln( mD );
    writeln( mF );
    writeln( mG );
    *)

    // unlock it
    mCriticalSection.Leave;
    end;
    end;
    end;
    end;

    procedure TCriticalProducer.Execute;
    begin
    while not Terminated do
    begin
    with mSharedCopy do
    begin
    mCriticalSection.Enter;

    mA := mA + 1;
    mB := mB + 2;
    mC := mC + 3;
    mD := 'Hello: ' + IntToStr(mA);
    mF := mF + 4;
    mG := mG + 5;
    mRuns := mRuns + 1;

    mCriticalSection.Leave;
    end;
    end;
    end;

    procedure TCriticalConsumer.Execute;
    begin
    while not Terminated do
    begin
    with mSharedCopy do
    begin
    // Sleep( 1000 );

    mCriticalSection.Enter;

    // Let's do something crazy instead to full test it

    mA := mA + 1;
    mA := mB;
    mC := mC + 3;

    (*

    writeln('Critical:');



    writeln( mA );
    writeln( mB );
    writeln( mC );
    writeln( mD );
    writeln( mF );
    writeln( mG );
    *)

    mCriticalSection.Leave;
    end;
    end;
    end;

    procedure ClearCopy( ParaCopy : TSharedData );
    begin
    with ParaCopy do
    begin
    mLocked := false;
    mA := 0;
    mB := 0;
    mC := 0;
    Pointer(mD) := nil;
    mF := 0;
    mG := 0;
    end;
    end;

    procedure Main;
    var
    mProducer : TProducer;
    mConsumer : TConsumer;

    mCriticalProducer : TCriticalProducer;
    mCriticalConsumer : TCriticalConsumer;

    begin
    writeln('program started');

    ClearCopy( mProducerCopy );
    ClearCopy( mConsumerCopy );
    ClearCopy( mSharedCopy );

    mProducerCopy.mCriticalSection := TCriticalSection.Create;
    mConsumerCopy.mCriticalSection := TCriticalSection.Create;
    mSharedCopy.mCriticalSection := TCriticalSection.Create;

    // perform locked test
    mProducer := TProducer.Create(True);
    mProducer.FreeOnTerminate := false;

    mConsumer := TConsumer.Create(True);
    mConsumer.FreeOnTerminate := false;

    // wait 1 second so program can be loaded
    Sleep( 1000 );

    mProducer.Resume;
    mConsumer.Resume;

    sleep(10000);

    mConsumer.Terminate;
    mProducer.Terminate;

    mConsumer.WaitFor;
    mConsumer.Free;

    mProducer.WaitFor;
    mProducer.Free;

    // perform critical test

    mCriticalProducer := TCriticalProducer.Create(True);
    mCriticalProducer.FreeOnTerminate := false;

    mCriticalConsumer := TCriticalConsumer.Create(True);
    mCriticalConsumer.FreeOnTerminate := false;

    // wait 1 second so program can be loaded
    Sleep( 1000 );

    mCriticalProducer.Resume;
    mCriticalConsumer.Resume;

    sleep(10000);

    mCriticalConsumer.Terminate;
    mCriticalProducer.Terminate;

    mCriticalConsumer.WaitFor;
    mCriticalConsumer.Free;

    mCriticalProducer.WaitFor;
    mCriticalProducer.Free;

    mProducerCopy.mCriticalSection.Free;
    mConsumerCopy.mCriticalSection.Free;
    mSharedCopy.mCriticalSection.Free;

    WriteLn('Locked Producer Runs : ', mProducerCopy.mRuns );
    WriteLn('Critical Producer Runs: ', mSharedCopy.mRuns );

    writeln('press enter to exit');
    readln;

    writeln('program finished');
    end;

    begin
    try
    Main;
    except
    on E:Exception do
    Writeln(E.Classname, ': ', E.Message);
    end;
    end.

    // *** End of Code ***

    Again Enjoy LOL

    I am starting to be like you: Writing useless code LOL ?!? ???

    Bye,
    Skybuck.



  13. Re: UDP Speed Test Version 2.93 Now Available !

    "Skybuck Flying" wrote in message
    news:fcq5em$ihb$1@news3.zwoll1.ov.home.nl...
    > Hi,
    >
    > I have created a little test/benchmark program, to compare these "CAS"
    > locking/unlocking ideas against critical sections.

    [...]

    Well, that program did not have lock-free code in it; you are still using
    locks. Try_Lock is not the same as lock-free CAS update. You basically
    comparing:

    if (try_lock(...) {

    unlock();
    }

    with:

    lock(...)

    unlock(...)


    That's lock-based vs. lock-based...



    For a lock-free vs. lock-based test of a counter, the code can look like
    this:

    /* lock-free counter */
    void inc(int volatile *psrc) {
    int cmp;
    do {
    cmp = *psrc;
    } while(! CAS(psrc, cmp, cmp + 1));
    }

    /* lock-based counter */
    void inc(int volatile *psrc) {
    lock();
    (*psrc)++;
    unlock();
    }


    Once you hit the lock-based code with multiple-threads you will see the
    negative effect of blocking occur. Here is some Delphi code you can look at:

    http://groups.google.com/group/comp....88f35820683e7b

    The author of that code was trying to wrap up some functionality of my
    AppCore library. I would examine his Delphi code. Humm... Where can I get a
    good Delphi compiler and IDE Skybuck? I guess I can fool around with
    something and perhaps be better able to help to write a lock-free algorithm
    in it.


  14. Re: UDP Speed Test Version 2.93 Now Available !


    "Skybuck Flying" wrote in message
    news:fcq69t$5uh$1@news6.zwoll1.ov.home.nl...
    > Yup the TryLock method I wrote is probably the same as
    > TCriticalSection.TryEnter

    [...]

    Bingo! :^)


  15. Re: UDP Speed Test Version 2.93 Now Available !

    Try one of these Delphi versions:

    http://cc.codegear.com/free/delphi

    I myself have CodeGear Delphi 2007.

    You could try one of the personal editions so it doesn't expire I think.

    Also the "minimum" Delphi version is called:

    Turbo Delphi Explorer.

    I don't quite understand the difference between Turbo Delphi Explorer and
    Delphi 2007, since I never tried Turbo Delphi Explorer.

    But the screenshots look similiar. Turbo Delphi Explorer is probably just a
    stripped down version of Delphi 2007.

    http://www.codegear.com/products/turbo

    Maybe I should try it sometime... But stripped down versions kinda scare
    me.. I am scared I might miss some important feature... or I am scared I
    can't compile somebody elses code/website code

    I think for you Turbo Delphi Explorer might be enough to try out Win32 +
    Threading + GUI + IDE + Debugger and such development in Delphi/Pascal.

    Otherwise try Delphi 2005 Personal... but I think that one probably less
    good because it's older.

    I think Turbo Delphi Explorer just as new as Delphi 2007

    Bye,
    Skybuck.




  16. Re: UDP Speed Test Version 2.93 Now Available !


    "Chris Thomasson" wrote in message
    news:EJudnUkZvKd5AG3bnZ2dnUVZ_oytnZ2d@comcast.com. ..
    > "Skybuck Flying" wrote in message
    > news:fcq5em$ihb$1@news3.zwoll1.ov.home.nl...
    >> Hi,
    >>
    >> I have created a little test/benchmark program, to compare these "CAS"
    >> locking/unlocking ideas against critical sections.

    > [...]
    >
    > Well, that program did not have lock-free code in it; you are still using
    > locks. Try_Lock is not the same as lock-free CAS update. You basically
    > comparing:
    >
    > if (try_lock(...) {
    >
    > unlock();
    > }
    >
    > with:
    >
    > lock(...)
    >
    > unlock(...)
    >
    >
    > That's lock-based vs. lock-based...


    There is a difference:

    The first one will continue.

    The second one will block.

    So it's continued-lock-based vs blocking-lock-based

    > For a lock-free vs. lock-based test of a counter, the code can look like
    > this:


    What you describe below is not really lock free.

    It's actually worse than my "continued lock based" method.

    At least my method doesn't block.

    Your method "blocks" because of the while loop.

    > /* lock-free counter */
    > void inc(int volatile *psrc) {
    > int cmp;
    > do {
    > cmp = *psrc;
    > } while(! CAS(psrc, cmp, cmp + 1));
    > }
    >
    > /* lock-based counter */
    > void inc(int volatile *psrc) {
    > lock();
    > (*psrc)++;
    > unlock();
    > }
    >


    You see, you think you invented something, but in fact it's even slightly
    worse

    Bye,
    Skybuck.



  17. Re: UDP Speed Test Version 2.93 Now Available !

    "Skybuck Flying" wrote in message
    news:fcq7ur$qu5$1@news6.zwoll1.ov.home.nl...
    >
    > "Chris Thomasson" wrote in message
    > news:EJudnUkZvKd5AG3bnZ2dnUVZ_oytnZ2d@comcast.com. ..
    >> "Skybuck Flying" wrote in message
    >> news:fcq5em$ihb$1@news3.zwoll1.ov.home.nl...
    >>> Hi,

    [...]
    > What you describe below is not really lock free.
    >
    > It's actually worse than my "continued lock based" method.


    Using try lock is nothing new:

    http://groups.google.com/group/comp....e38e27df971e0d

    http://groups.google.com/group/comp....0fb2901b42e447



    > At least my method doesn't block.
    >
    > Your method "blocks" because of the while loop.


    You confusion the work block with spin; blocking imples a thread has wait on
    a kernel waitset which is different than spinning on CAS. My example was
    lock-free; not wait-free. Anyway, here is a loop-less version that does not
    spin:


    /* returns previous value using wait-free */
    bool count_add_try(int volatile *psrc, int count, int *pprev) {
    int const cmp = *psrc;
    if (CAS(psrc, cmp, cmp + count))) {
    if (pprev) { *pprev = cmp; }
    return true;
    }
    return false;
    }

    /* returns previous value using lock-free */
    int count_add(int volatile *psrc, int count) {
    while(! count_add_try(psrc, count));
    }


    /* non-blocking example */
    static int volatile shared_count = 0;

    multiple_threads() {
    for(; {
    int prev;

    if (count_add_try(&shared_count, 1, &prev)) {
    /* update gui with previous counter value */

    } else {
    /* work on something else */
    }

    /* do some work */
    }
    }






    > You see, you think you invented something, but in fact it's even slightly
    > worse


    I don't claim to invent using CAS in a loop. That has been around for ages.
    I advise you to read the following post in great detail:

    http://groups.google.com/group/comp....3d2d6f90563eda



  18. Re: UDP Speed Test Version 2.93 Now Available !

    Maybe you are re-implementing something that has already been implemented ?!

    The big question is:

    Do CriticalSections.Enter, Leave and TryEnter spin on 'cas' or do they do
    something else (On Windows XP) ?

    Bye,
    Skybuck.



  19. Re: UDP Speed Test Version 2.93 Now Available !

    "Skybuck Flying" wrote in message
    news:fcq7pi$8g4$1@news6.zwoll1.ov.home.nl...
    > Try one of these Delphi versions:
    >
    > http://cc.codegear.com/free/delphi
    >
    > I myself have CodeGear Delphi 2007.

    [...]
    > But the screenshots look similiar. Turbo Delphi Explorer is probably just
    > a stripped down version of Delphi 2007.
    >

    [...]

    I downloaded turbo Delphi. I will play around with it for a while and see if
    I can get anywhere. BTW, there is no pesky garbage collector in this
    language right?


  20. Re: UDP Speed Test Version 2.93 Now Available !

    "Skybuck Flying" wrote in message
    news:fcr723$uj7$1@news2.zwoll1.ov.home.nl...
    > Maybe you are re-implementing something that has already been implemented
    > ?!
    >
    > The big question is:
    >
    > Do CriticalSections.Enter, Leave and TryEnter spin on 'cas' or do they do
    > something else (On Windows XP) ?


    CriticalSections have to perform interlocked rmw and memory barrier
    instructions to enforce the coherency of a piece of state that can be
    considered a proxy. For example, take a look at my implementation of
    Peterson's classic algorithm:

    http://groups.google.com/group/comp....9c0658e2607317

    What does the operations on the shared variables the algorithm has to
    perform actually have to do with the datum contained in its critical
    section?

    See I can lock and unlock this mutual exclusion technique multiple times and
    it won't touch any state whatsoever... Example:

    lock();
    unlock();


    Useless because the 'lock/unlock' operations DO NOT touch user data; agreed?
    I can lock and unlock all day long, which means I am using expensive
    interlocked rmw and membar instructions for nothing. Here is the kicker... A
    lock-free algorithm can use the same instructions contained in the 'lock'
    operation of a mutex to mutate actual user state.

    PLEASE READ THE FOLLOWING:

    http://groups.google.com/group/comp....3d2d6f90563eda


    read it once... Read it again... and again.



    You should gather that the instructions that a mutex uses operates on the
    state of the lock; not ANY state contained in any of its critical-sections.
    A lock-free operation either modifies user shared state, or not. A lock has
    to work on its on state BEFORE it can even think about allowing the
    programmer of its various critical sections to issue loads and stores on
    shared data. Again, lock-free operation either mutates actual user state, or
    nothing. Lock-based has to play around with its own PERSONAL state before it
    can decide to let anybody do anything.


    Another try:


    a lock-free operation on a simple monotonic counter would either increment
    the counter, or fail. A lock-based operation would have to try and modify
    its own state that has nothing to do with the counter BEFORE it can do
    anything. This has overheads... BTW, when the lock-based algorithm swings
    its private state into something that says it can proceed, well, it
    subsequently will be forced to undo that state change in the form of an
    unlock operation. Of course the unlock will be calling membars (e.g.,
    #LoadStore | #StoreStore to be exact using SPARC notation) to actually
    perform the mutation which allows another thread to get a chance.


    Does that make any sense to you at all?



+ Reply to Thread
Page 3 of 4 FirstFirst 1 2 3 4 LastLast