Thread: Conceptual notion of a function/procedure which continuously repeats its methods

  1. #1
    Registered User
    Join Date
    Jan 2016
    Posts
    43

    Conceptual notion of a function/procedure which continuously repeats its methods

    You'll forgive me. This is probably CS 101 but I would still like to explore this elementary topic.

    I have a program which continuouly runs itself with little to no user input. The fact it runs itself means it has to repeat many of its functions over and over again. What is the programming norm to implement such a design?

    I thus far have been putting the repeating functions in a while(true) loop. However for some reason (I may or may not be wrong) it's my understanding that this is frowned upon. The alternative is to probably implement the functions to run recursively whereby some of the functions call themselves up to some exit condition.

    The problem I am having with either scenario is that the program ends up hogginng CPU cycles. A couple of threads implemented this way and the CPU usage is > 300% in most cases. I have added in some sleep() functions and the CPU usage certainly goes down, but this unnecessarily increases program latency which isn't a desired feature required. Using sleep() is definitely frowned upon.

    I would appreciate some thoughts please.

  2. #2
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    This sounds like it should be solved by event-driven programming... I think we might need some more info for your use-case.

  3. #3
    Registered User
    Join Date
    Jan 2016
    Posts
    43
    Interesting. I would have thought quite the opposite in fact. There are no events being used or generated. Most programs work on the paradigm that an event such as user input "drives" the program to do something. In this case howver the program runs autonomously.

  4. #4
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Quote Originally Posted by wiqxlzxsxj View Post
    I thus far have been putting the repeating functions in a while(true) loop. However for some reason (I may or may not be wrong) it's my understanding that this is frowned upon.
    Nothing to frown about. An application main execution loop (aka main loop, aka main event loop) is one of the most common strategies in software development and is an essential design in many types of applications.

    A while(true) loop is perfectly valid indicator of a limitless loop whose exit conditions are defined inside. It has an especially powerful semantic value when it wishes to indicate that the loop is in fact meant to be endless until the exit conditions are met. While (true) constructs are to be frown only when they do not convey the meaning of an endless loop. That is, loops that have a clear limit of iterations. Consider the following logic:

    Code:
    // A
    while (true) {
        draw_menu;
        wait_for_input;
        if (input == 'q') break;
        process_input;
        clear_screen;
    }
    
    // B
    while (true) {
        read_list_node;
        process_node;
        move_to_next_node;
        if (node == NULL) break;
    }
    Despite both loops having exit conditions (as they should), loop A is being better described. It is meant to be endless, unless a specific condition terminates it. One could say the while (true) construct is a valid semantic. There is no limit imposition to the number of cycles. There are only exit conditions.

    Loop B on the other hand is being poorly described. It is not meant to be an endless loop. It has a limit which is the size of the list. And that limit is at least one of exit conditions.

    Naturally you can turn limitless loops like A into having the exit condition on the loop declaration. But you aren't required, and your code will under many circumstances become poorer in semantics, because you are removing a powerful indicator of the true meaning of the loop. Whereas loop B does need to be changed for the exact same reason that in its present state it is not representing its true meaning.

    while (true) loops are frowned upon because of B loops. Most of the time your loops are of the B type and these type of loops shouldn't be expressed as endless loops. Not only that is a false depiction of their nature, but exit conditions buried inside the loop body may make it harder to understand.
    Last edited by Mario F.; 10-24-2016 at 06:56 PM.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  5. #5
    Registered User
    Join Date
    Jan 2016
    Posts
    43
    Thanks for this description Mario. i appreciate the effort in clarifying the identity of a loop.

    OK.. so considering a while(1) loop, I've inserted a series of functions inside the loop so that the same procedures keep repeating themselves. Can I implement this more effectively using a callback function like so:

    Code:
    static void manifest_callback(struct *ptr)
    {
        function1(ptr);
        function2(ptr);
        .
        .
        .
    }
    
    void manifest(struct *ptr, void (*callback)(struct *ptr))
    {
        while(1)
        {
            callback(ptr);
            
            if(exit cond) break;
        }
    }
    
    void *thread_func(void *PTR)
    {
        struct *ptr = PTR;
     
        manifest(ptr, manifest_callback);
    
             return NULL;
    }
    The only issue is that CPU usage still goes to > 300%.
    Last edited by wiqxlzxsxj; 10-25-2016 at 06:00 PM.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    You say there are no user events, but what is the program doing?

    If your program is processing data from some external source (network, file), then you should be doing something like this
    Code:
    if ( waitForData() ) {
      // read data and process
    }
    Not this
    Code:
    if ( pollForData() ) {
      // read data and process
    } else {
      sleep(tick);
    }
    In Unix/Linux systems, almost all the data a program can receive is obtained via file descriptors. If you're reading file descriptors in your program, then the waitForData() function is called select().



    Unless your program is doing something computational (like prime factorisation), you shouldn't be going round in infinite loops repeatedly polling to see if there is more data to process, then throwing in a scattering of 'voodoo' to try and regulate excessive CPU usage.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Jan 2016
    Posts
    43
    Yoou're right, this is probably what I need. There is no other way but to use a timeout up to some condition of a file descriptor. I also tried using a semaphore but it would seem one way or another a delay in the loop has to be used.

    Using a FD, I have now constructed the following statements. Although I'm not clear if the logic entirely correct.

    Code:
    quit = false;
    
    /* FD */
    fd_set fdset;
    struct timeval timeout;
    
    while(!quit)
    {
        repeating_function();
            
        if(!quit)
        {
            FD_ZERO(&fdset);
                
            if(var_changes)
                FD_SET(0, &fdset);
            
            else
            {
                timeout.tv_sec = 1 / 10;
                timeout.tv_usec = 100;
                  
                select(1, &fdset, NULL, NULL, &timeout);
            }
        }
    }
    I want to monitor var and if it chhanges only then I wish to call the repeating function.
    Last edited by wiqxlzxsxj; 10-26-2016 at 08:46 AM.

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    > FD_SET(0, &fdset);
    I thought you said your program had no user interaction?

    > I want to monitor var and if it chhanges only then I wish to call the repeating function.
    OK, and what changes var in the first place?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    Registered User
    Join Date
    Jan 2016
    Posts
    43
    There is no user interaction.

    var is changed concurrently from another thread which is also running.

  10. #10
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Mutexes and condition variables are how threads signal one another.

    Though to be honest, I rather suspect you've over-complicated the whole thing by attempting to "solve" some imagined problem by adding threads in the first place.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  11. #11
    Registered User
    Join Date
    Jan 2016
    Posts
    43
    The overall function of the program is to get data from the internet, process that data and then to format the data on the terminal. It's too large to post here. But as I am interested in low latency and performance I have implemented a design which is such that one thread (the main programme thread) gets the data, a second thread formats/processes it into respective variables; and then the third thread prints that data to the screen.

    This could be done in one thread alone whereby the data is fetched, processed, and displayed sequentially. However due to the flexibility of the problem I decided to use multiple threads so that all three processes can run at the same time. This makes good use of available hardware resources and at the same time adheres to the design philosophy.

    In each thread there is a while(1) loop so that the process keeps repeating itself. I could add a usleep delay to each while(1) loop in each thread in order to delay the cycles. This certainly helps to reduce CPU load. But philosophically (and to an extent practically) adding usleep adds a fixed delay which I'm not comfortable with. Remember from the outset I've been after a design which focusses on low latency by working in parallel.

    The issue at this point is to smarten the use of CPU cycles by trimming away unnecessary cycles. The reasoning behind our earlier discussion was to continue with the while(1) loop based on a certain change of a variable (like say fresh data), and to momentarilty halt the loop when this variable didn't change. This was what I had in mind:

    Code:
    while(1)
    {
        FD_ZERO
    
        if(var_value != last_var_value)
            FD_SET
    
        else
        {
            set max delay
            select()
        }
    
        some_function();
    }

  12. #12
    Registered User
    Join Date
    Jan 2016
    Posts
    43
    How can I set a FD based on a change of variable?

  13. #13
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Oh God, stop using `while (true)` loops. You need to `poll` or some such other mechanism. Basically, invoke inter-process communication and treat this like a client-server problem. You have one thread that acts as the server and when a client opens a socket connection, offload the task to a worker thread and then do whatever you need to. Just please don't write a `while (true)` loop.

  14. #14
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Quote Originally Posted by wiqxlzxsxj View Post
    This could be done in one thread alone whereby the data is fetched, processed, and displayed sequentially. However due to the flexibility of the problem I decided to use multiple threads so that all three processes can run at the same time. This makes good use of available hardware resources and at the same time adheres to the design philosophy.
    The operations are entirely sequential. You need the data before you can process it and you need to process it before you can output it. There's no benefit in multi-threading here, particularly because the initial operation of fetching the data from the internet has higher latency than the two other threads combined.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  15. #15
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    I agree with MutanJohn, seems like program should be event driven. You could use message queues similar to how Windows apps work, where each thread has a input queue that it waits for to become non-empty. Each thread would wait for and retrieve one message from it's input queue, process the message, and then enqueue the message to the next threads input queue. The "last" thread in the chain would enqueue the message to a free pool for that the "first" thread retrieves messages from. I/O driven threads would also wait for I/O's to complete (sequence, get a message, perform I/O, send the message to next thread).

    One issue is what to do if the display thread is not keeping up with the data collection thread. Assuming the display thread is the "last" thread, it could monitor the free pool and if the number of messages in the free pool dropped below some threshold, it would start skipping display outputs to catch back up.

    This messaging interface is how I've implemented data collection programs, and also how most of the embedded multi-threaded applications I've seen are implemented.
    Last edited by rcgldr; 10-26-2016 at 04:11 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Conceptual ambiguity "function prototype"
    By password636 in forum C Programming
    Replies: 4
    Last Post: 04-02-2009, 12:48 PM
  2. c library function conceptual doubt
    By agarwaga in forum C Programming
    Replies: 2
    Last Post: 05-11-2006, 11:34 AM
  3. notion confusion
    By volk in forum C++ Programming
    Replies: 7
    Last Post: 05-21-2003, 01:15 PM

Tags for this Thread