a C++ suggestion while, also loop?

Nov 18, 2016 at 5:05am
Ok So I want to make a thing that continuously adds 1 to a variable, but doing a while loop stops the whole program.

Then I got thinking what if there was a "While also loop?"
Something like this:
1
2
3
4
5
6
7
8
While(game  == true)
{
 //Does the main loop code
}
also
{
 //Does any additional code that runs at the same time the while loop is going
}


If there is already a way to do this in C++ please tell me. Thanks for reading
Last edited on Nov 18, 2016 at 5:05am
Nov 18, 2016 at 5:11am
Note: The following code may behave non-deterministically.
1
2
3
4
5
6
7
std::atomic<int> var = 0;
std::atomic<bool> continue_running = true;
std::thread thread([&var, &continue_running](){ while (continue_running) var++; });
for (int i = 0; i < 1000; i++)
    std::cout << var << std::endl;
continue_running = false;
thread.join();
Nov 18, 2016 at 10:03am
closed account (48T7M4Gy)
Written for Java but nevertheless deals with 'atomic'.

http://stackoverflow.com/questions/15054086/what-does-atomic-mean-in-programming
Last edited on Nov 18, 2016 at 10:04am
Nov 21, 2016 at 4:01am
"Non-deterministic" doesn't even imply "concurrent", so there's a chance that OP won't (or possibly can't) get what he asked for.

I doubt that concurrency is what OP needs, but the question was clear.
Nov 21, 2016 at 4:56am
closed account (48T7M4Gy)
... make a thing that continuously adds 1 to a variable, but doing a while loop stops the whole program.


The addition of 1 to the variable referred to in the OP is one which could/should be handled by concurrent programming, ie in a separate thread.

One aspect of the calculation is atomicity to avoid non-deterministic (or apparently random or apparently undefined) behaviour.

OP needs to be more specific about the purpose of the incrementing function in relation to the overall programming requirement to make any further comment on it. eg increment speed and timing etc, but the wait structure is addressed.
Nov 21, 2016 at 6:13am
@kemort
Well of course the atomic counter increases monotonically, but isn't the code "non-deterministic" in the sense that val will be incremented an unpredictable number of times, thanks to timing and the implementation? Maybe my terminology is a bit off.

Last edited on Nov 21, 2016 at 6:14am
Nov 21, 2016 at 6:43am
Yes, the code may behave non-deterministally due to various factors, such as timing details at the hardware level, implementation details in the OS's scheduling algorithm, etc. This causes var to be incremented by random amounts each time through the loop. The usage of std::atomic guarantees that var will always be read and updated in a consistent manner (i.e. never being half-updated).

"Non-deterministic" doesn't even imply "concurrent", so there's a chance that OP won't (or possibly can't) get what he asked for.
I have no idea what you're talking about.
Yes, non-determinism doesn't imply concurrency, but threads are both concurrent and parallel.
OP didn't imply he wanted deterministic behavior, but if he does, his question is underspecified.

[quote]I doubt that concurrency is what OP needs[/qoute]Doing one thing "while also" doing another is the definition of concurrency.

Modelling deterministic concurrency, while possible, is in the general case far more complicated.
For example in OP's example, to concurrently and deterministically increment a variable while a loop runs, it might be sufficient to do this:
1
2
3
4
while (/*...*/){
    f();
    var++;
}
Or this:
1
2
3
4
while (/*...*/){
    f();
    var += step;
}
Or even:
1
2
3
4
5
6
7
while (/*...*/){
    f();
    if (++var2 == step2){
        var += step;
        var2 = 0;
    }
}

But things get really complicated really fast:
1
2
3
4
while (/*...*/){
    f();
    g();
}
How do you coordinate concurrent state changes by the two functions? This is a rabbit hole that goes really deep, up to and including implementing a virtual machine where instructions run atomically.
Nov 21, 2016 at 7:11am
I have no idea what you're talking about.

I meant that your code does not guarantee that the value is actually incremented at the same time the loop runs. As you indicated, if OP wants deterministic behavior he should have asked for it.

I doubt that concurrency is what OP needs
Doing one thing "while also" doing another is the definition of concurrency.

To me, it looks like OP has posed an XY problem ( http://xyproblem.info/ ) and therefore doesn't need the solution. But we'll need OP's input to discuss that further.

However, your examples indicate to me that I apparently don't understand the difference between "concurrent" and "parallel".

How is
1
2
3
4
while (/*...*/){
    f();
    var++;
}

a concurrent process? It's obviously serial, not parallel; there's something I'm missing.
Last edited on Nov 21, 2016 at 7:20am
Nov 21, 2016 at 7:22am
closed account (48T7M4Gy)
@mbozzi

I italicized 'apparently' to emphasize the possible appearance of randomness, rather than actual randomness or unpredictability of the program result. Any difference between the two would need close examination beyond what's obvious here with the OP.

If (lack of) atomicity is the cause then helios' suggestion comes into play.

The added problem comes with timing. Who knows where that goes without more information than we have?

However, it seems we all agree that threads, appropriately designed, answer the OP's question. Be careful though there appear to be traps in the rabbit hole and I don't doubt it ;)

Nov 21, 2016 at 1:33pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <thread>
#include <chrono>

long long int value; // excuse global variable; just to make things simple

void increment()
{
    while (value != 100000000)
    {
        ++value;
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
}

int main()
{
    value = 0;

    std::thread t1(increment);

    while (value != 100000000)
    {
        std::cout << value;
        std::cin.get(); // every time enter is pressed display current value
    }

    t1.join();

    return 0;
}
Last edited on Nov 21, 2016 at 1:52pm
Nov 21, 2016 at 2:14pm
How is [...] a concurrent process? It's obviously serial, not parallel
Two processes are concurrent to each other if at any point in time both have started and neither has completed.
For example, if you need to bake a cake and prepare some sandwiches, going back and forth between the two tasks is a way of doing them concurrently.

Two processes are parallel if they are concurrent and they execute non-stop or in a manner that's indistinguishable from executing non-stop.
Asking another person to prepare the sandwiches while you bake the cake is a way of doing both tasks in parallel.

In my example, the task of executing f() in a loop and the task of incrementing var in a loop are two separate tasks whose loops have been merged so they can execute concurrently. It's a form of very explicit and manual concurrency. There are more powerful forms, such as cooperative multitasking (i.e. coroutines) which is also concurrent, non-parallel, and deterministic. And of course threads, where you abandon determinism and let the machine figure out how to order operations.

boost lexical cast: Note that reading and writing data in separate threads without memory barriers or atomic operations has undefined behavior in multisocket platforms. As in, the lack of guarantees on the part of the hardware causes unbounded non-determinism.
Nov 21, 2016 at 2:19pm
Just for fun:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <future>
#include <functional>
#include <thread>
#include <chrono>

struct statement { std::function< void() > fn ; };

struct compound_statement { statement a ; statement b ; };

struct condition
{
    std::function< bool() > cond ;
    void operator, ( compound_statement cs ) const
    {
        auto future = std::async( std::launch::async, [&] { while( cond() ) cs.a.fn() ; } ) ;
        while( cond() ) cs.b.fn() ;
    }
};

compound_statement operator and ( statement a, statement b ) { return {a,b} ; }

template < typename FN > condition While( FN fn ) { return {fn} ; }
template < typename FN > statement Do( FN fn ) { return {fn} ; }
template < typename FN > statement Also( FN fn ) { return {fn} ; }

int main()
{
    using namespace std::this_thread ;
    using namespace std::literals ;

    std::atomic<int> i {20} ;
    std::atomic<int> j {80} ;
    const auto condition = [&] { return i < j ; } ;
    const auto this_thing = [&] { std::cout << '1' << std::flush ; ++i ; sleep_for(100ms) ; } ;
    const auto something_else = [&] { std::cout << '2' << std::flush ; --j ; sleep_for(50ms) ; } ;

    While(condition), Do(this_thing) and Also(something_else) ;
    
    std::cout << "\n\ni == " << i << "  j == " << j << '\n' ;
}

http://coliru.stacked-crooked.com/a/124c39427a6cbf09
http://rextester.com/KGP86246
Nov 21, 2016 at 3:48pm
I missed this bit in my last reply:
I italicized 'apparently' to emphasize the possible appearance of randomness, rather than actual randomness or unpredictability of the program result.
No, threads are capable of introducing true randomness into a program's behavior, depending on the hardware and OS implementations. It's possible to create a hardware platform where the behavior of multithreaded programs can only be predicted by Maxwell's demon, and yet single-threaded programs execute deterministically.
Nov 21, 2016 at 4:02pm
closed account (48T7M4Gy)
I have covered both apparent and actual randomness in my full comment so there is no denial on my part that threads are capable of true randomness (indeterminate behaviour), for whatever reason. It would be silly to make such a claim.
Nov 21, 2016 at 4:35pm
But it came across as if you were saying that atomics could mitigate random behavior. Atomics prevent inconsistencies, but randomness may still show up in threaded programs.
Dec 22, 2016 at 3:28am
Just for fun:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <future>
#include <functional>
#include <thread>
#include <chrono>

struct statement { std::function< void() > fn ; };

struct compound_statement { statement a ; statement b ; };

struct condition
{
    std::function< bool() > cond ;
    void operator, ( compound_statement cs ) const
    {
        auto future = std::async( std::launch::async, [&] { while( cond() ) cs.a.fn() ; } ) ;
        while( cond() ) cs.b.fn() ;
    }
};

compound_statement operator and ( statement a, statement b ) { return {a,b} ; }

template < typename FN > condition While( FN fn ) { return {fn} ; }
template < typename FN > statement Do( FN fn ) { return {fn} ; }
template < typename FN > statement Also( FN fn ) { return {fn} ; }

int main()
{
    using namespace std::this_thread ;
    using namespace std::literals ;

    std::atomic<int> i {20} ;
    std::atomic<int> j {80} ;
    const auto condition = [&] { return i < j ; } ;
    const auto this_thing = [&] { std::cout << '1' << std::flush ; ++i ; sleep_for(100ms) ; } ;
    const auto something_else = [&] { std::cout << '2' << std::flush ; --j ; sleep_for(50ms) ; } ;

    While(condition), Do(this_thing) and Also(something_else) ;
    
    std::cout << "\n\ni == " << i << "  j == " << j << '\n' ;
}

http://coliru.stacked-crooked.com/a/124c39427a6cbf09
http://rextester.com/KGP86246


I'm guessing that is for making the while also loop.
Dec 22, 2016 at 3:54am
> I'm guessing that is for making the while also loop.

Yes. Just for fun.
Topic archived. No new replies allowed.