cmultithreadingreturnexitthreadx

How can I exit a function as soon as a certain condition is met (without checking it at every line)?


I am developing a multi-threaded application. One of the threads is dedicated to handling an alarm system, which plays a certain alarm (sequence of specific tones) according to the alarm case. There's also an option to mute the alarm, by raising a flag from another thread. Whenever an alarm is muted, I want my program to immediately stop the alarm and not go through all the sequence. Below is a toy example of how my code is structured:

static int mute = 0;
static int current_alarm = 0;

void play_alarm_2 (void)
{
play_g_tone();
sleep(30);
play_a_tone();
sleep(20);
. . .
} 

void play_alarm_1 (void)
{
play_c_tone();
sleep(10);
play_f_tone();
sleep(20);
. . .
} 

void set_mute_status (int mute_status)
{
mute = mute_status;
}
void set_current_alarm (int alarm)
{
current_alarm = alarm;
}

int main()
{
    for(;;)
    {
    switch(current_alarm)
        case 1:
            play_alarm_1();
        case 2:
            play_alarm_2();
        . . .
    }
}

Other threads set the alarm case and the muting option. Now for example, if the alarm thread is currently inside play_alarm_2 and is playing the g_tone, if the user suddenly mutes the alarm, I would like to exit the function play_alarm_2 (the g_tone can finish to play, it doesnt have to cut it short necessarly). A stupid way to do it would be to add an every other line:

void play_alarm_2 (void)
{
if (mute)
    return

play_g_tone();

if (mute)
    return

sleep(30);

if (mute)
    return

play_a_tone();

if (mute)
    return

sleep(20);
. . .
} 

Which again looks a bit stupid but does it solves my problem. I could also set up a macro maybe for it. But my question is, is there a more proper way to do this? Probably there is a solution that includes introducing another thread, but I would avoid it If i can. If really there's no way to do this without another thread, what would be the proper way to implement this?

P.S: This code will go on an embedded system and I am using ThreadX.


Solution

  • A sketch of "how to do this":

    #define N 6 // 0-5 steps
    for( int i = 0; ; i = (i+1) % N ) { // 0-1-2-3-4-5-0-1-2...
        switch( i ) {
            case 0: play_a_tone(); break;
            case 2: play_g_tone(); break;
            case 4: play_c_tone(); break;
    
            case 1:
            case 3:
                sleep(30);
                break;
            case 5:
                sleep(200);
                break;
        }
        if( mute ) return;
    }
    

    If the only thing happening in the function is this loop, you could even:

    for( int i = 0; !mute; i = (i+1) % N ) {
    

    and wouldn't need the extra if() at the bottom of the loop...


    UPDATE:
    Happened across this and wanted to post an 'improvement' that clearly separates the data from the functionality:

    struct {
        void (*tone)();
        int dur;
    } sqnc[] = {
        { play_a_tone,  30 }, // repeatedly played in sequence
        { play_g_tone,  30 },
        { play_c_tone, 200 },
        { play_f_tone,  30 },
    };
    const int N = sizeof sqnc/sizeof *sqnc;
    
    for( int i = 0; !mute; i = (i+1) % N ) {
        sqnc[i].tone(); if( !mute ) sleep( sqnc[i].dur );
    }
    

    This suggests it could be made even simpler if the separate play_X_tone() functions were combined into a single function that takes and uses a parameter. Haven't seen that code, so this is just an observation.

    (Just put Donna Summer's "I Feel Love" on the stereo... Multiple threads?? You're on your way to re-inventing the 'digital sequencer'. :-))