0

good evening/morning,

I'm experimenting with the concepts of pthreads and have a small program written to test various pieces of it. So, I have three threads created in the main function, and then the first thread asks you for input. I want the threads to execute in the order of USER_INTERFACE_THREAD, PIC_COMMUNICATION_THREAD, then SEND_TO_SERVER_THREAD, and finally repeat. I want only one thread running at a time, so I use a lock method:

#include <pthread.h>
#include <stdio.h>

#define TRUE (1)
#define FALSE (0)

void *Switch_statement();
void *Server_function();
void *User_choices();

pthread_t SEND_TO_SERVER_THREAD;
pthread_t PIC_COMMUNICATION_THREAD;
pthread_t USER_INTERFACE_THREAD;
pthread_mutex_t lock;
pthread_cond_t cond;

int userinput;
int UI_THREAD_RUNNING = TRUE;
int PIC_THREAD_RUNNING = FALSE;
int SERVER_THREAD_RUNNING = FALSE;

int main()
{
    pthread_create(&USER_INTERFACE_THREAD, NULL, User_choices, NULL);   
    pthread_create(&PIC_COMMUNICATION_THREAD, NULL, Switch_statement, NULL);
    pthread_create(&SEND_TO_SERVER_THREAD, NULL, Server_function, NULL);

    pthread_join(USER_INTERFACE_THREAD, NULL);
    pthread_join(PIC_COMMUNICATION_THREAD, NULL);
    pthread_join(SEND_TO_SERVER_THREAD, NULL);
}



void *Switch_statement()
{

    while(1)
    {
        while(UI_THREAD_RUNNING || SERVER_THREAD_RUNNING)
            pthread_cond_wait(&cond, &lock);

        pthread_mutex_lock(&lock);
        switch(userinput) 
        {
            case 0:         
                    printf("case0");
                    break;
            case 1:                                     //RETRIEVE ADC CASE
                    printf("case1");    
                    break;
            case 2:
                    printf("case2");
                    break;  
            case 3:                                     //RESET CASE
                    printf("case3");
                    break;                          //EXIT THE PROGRAM
            case 4:
                    printf("case4");
                    break;
            default:
                    printf("Your entry is not a valid option! Try again \n");                   
        }
        PIC_THREAD_RUNNING = FALSE;
        SERVER_THREAD_RUNNING = TRUE;
        pthread_mutex_unlock(&lock);
    }
}

void *Server_function()
{
    while(1)
    {
        while(PIC_THREAD_RUNNING || UI_THREAD_RUNNING)
            pthread_cond_wait(&cond, &lock);

        pthread_mutex_lock(&lock);
        printf("SERVER FUNCTION");

        SERVER_THREAD_RUNNING = FALSE;
        UI_THREAD_RUNNING = TRUE;
        pthread_mutex_unlock(&lock);
    }
}

void *User_choices()
{
    while (1)
    {
        while (PIC_THREAD_RUNNING || SERVER_THREAD_RUNNING)
            pthread_cond_wait(&cond, &lock);

        pthread_mutex_lock(&lock);
        printf("Type 0-4: ");
        scanf("%i", &userinput);
        printf("past scanf");
        UI_THREAD_RUNNING = FALSE;
        PIC_THREAD_RUNNING = TRUE;
        pthread_mutex_unlock(&lock);    
    }
}

In my second thread, you can see that it checks the user input. I would also like the order of the threads to be reset back to the USER_INTERFACE_THREAD without going to the SERVER_THREAD if the user picks something that falls under the default case. I would also like all three threads to be terminated and the program to exit if the user clicks 3. So how can I implement this? I'm also not using an cond_signal commands. is that a bad thing? If so, how would I use these?

EDIT: Revised question to only focus on the issues I still have since I figured some out right after posting

I added the library and initialized my variables properly from what I know. So this issue keeps going on off, but sometimes my program hangs. If i use the cond_wait command, it hangs immediately. If i don't, a race condition is introduced and if thread 3 grabs the lock before thread 2, it hangs again. I tried to use a broadcast statement, but the same issue occurs. Am i supposed to use two separate locks to get this to work properly?

#include <pthread.h>
#include <stdio.h>
#include <stdbool.h>


void *Switch_statement();
void *Server_function();
void *User_choices();

pthread_t SEND_TO_SERVER_THREAD;
pthread_t PIC_COMMUNICATION_THREAD;
pthread_t USER_INTERFACE_THREAD;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int userinput;
int UI_THREAD_RUNNING = true;
int PIC_THREAD_RUNNING = false;
int SERVER_THREAD_RUNNING = false;

int main()
{
    pthread_create(&USER_INTERFACE_THREAD, NULL, User_choices, NULL);   
    pthread_create(&PIC_COMMUNICATION_THREAD, NULL, Switch_statement, NULL);
    pthread_create(&SEND_TO_SERVER_THREAD, NULL, Server_function, NULL);

    pthread_join(USER_INTERFACE_THREAD, NULL);
    pthread_join(PIC_COMMUNICATION_THREAD, NULL);
    pthread_join(SEND_TO_SERVER_THREAD, NULL);
}



void *Switch_statement()
{

    while(1)
    {
        while(UI_THREAD_RUNNING || SERVER_THREAD_RUNNING)
            pthread_cond_wait(&cond, &lock);

        pthread_mutex_lock(&lock);
        switch(userinput) 
        {
            case 0:         
                    printf("case0");
                    break;
            case 1:                                     //RETRIEVE ADC CASE
                    printf("case1");    
                    break;
            case 2:
                    printf("case2");
                    break;  
            case 3:                                     //RESET CASE
                    printf("case3");
                    break;                          //EXIT THE PROGRAM
            case 4:
                    printf("case4");
                    break;
            default:
                    printf("Your entry is not a valid option! Try again \n");                   
        }
        PIC_THREAD_RUNNING = false;
        SERVER_THREAD_RUNNING = false;
    pthread_cond_broadcast(&cond);
        pthread_mutex_unlock(&lock);
    }
}

void *Server_function()
{
    while(1)
    {
        while(PIC_THREAD_RUNNING || UI_THREAD_RUNNING)
            pthread_cond_wait(&cond, &lock);

        pthread_mutex_lock(&lock);
        printf("SERVER FUNCTION");

        SERVER_THREAD_RUNNING = false;
        UI_THREAD_RUNNING = true;
    pthread_cond_broadcast(&cond);
        pthread_mutex_unlock(&lock);
    }
}

void *User_choices()
{
    while (1)
    {
        while (PIC_THREAD_RUNNING || SERVER_THREAD_RUNNING)
            pthread_cond_wait(&cond, &lock);

        pthread_mutex_lock(&lock);
        printf("Type 0-4: ");
        scanf("%i", &userinput);
        printf("past scanf");
        UI_THREAD_RUNNING = false;
        PIC_THREAD_RUNNING = true;
    pthread_cond_broadcast(&cond);
        pthread_mutex_unlock(&lock);    
    }
}
Trever Wagenhals
  • 381
  • 5
  • 14
  • 2
    Your pthread mutex/cv usage is wrong. You seem to have forgotten to latch your mutex before entering into the thread-proc's while-loop. Remember, `pthread_cond_wait` requires you *own* the mutex before calling it. And the `pthread_mutex_lock(&lock);` after that is unnecessary, as you exit `pthread_cond_wait` once-again already owning the mutex, errors notwithstanding. [Perhaps **this** will help](http://stackoverflow.com/a/14925150/1322972). – WhozCraig Apr 14 '16 at 19:58
  • Don't define your own booleans. POSIX requires a C99 compiler, you have `` available. Also, your mutex and condition variable are not initialized to valid values. – EOF Apr 14 '16 at 20:00
  • fixed the things that you guys mentioned so far, obviously still have problems, but i'll read that page you referenced to see if i can figure it out. – Trever Wagenhals Apr 14 '16 at 20:14
  • @TreverWagenhals: You have not fixed your misuse of `pthread_cond_wait()` at all. You still pass a pointer to a mutex you don't hold. – EOF Apr 14 '16 at 20:24

1 Answers1

-1

Thanks to the link @WhosCraig supplied, I redid my code and it appears to be working:

#include <pthread.h>
#include <stdio.h>
#include <stdbool.h>


void *Switch_statement();
void *Server_function();
void *User_choices();

pthread_t SEND_TO_SERVER_THREAD;
pthread_t PIC_COMMUNICATION_THREAD;
pthread_t USER_INTERFACE_THREAD;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t CONDITION_UI = PTHREAD_COND_INITIALIZER;
pthread_cond_t CONDITION_PIC = PTHREAD_COND_INITIALIZER;
pthread_cond_t CONDITION_SERVER = PTHREAD_COND_INITIALIZER;

int userinput;
int UI_THREAD_RUNNING = true;
int PIC_THREAD_RUNNING = false;
int SERVER_THREAD_RUNNING = false;

int main()
{
    pthread_create(&USER_INTERFACE_THREAD, NULL, User_choices, NULL);   
    pthread_create(&PIC_COMMUNICATION_THREAD, NULL, Switch_statement, NULL);
    pthread_create(&SEND_TO_SERVER_THREAD, NULL, Server_function, NULL);

    pthread_join(USER_INTERFACE_THREAD, NULL);
    pthread_join(PIC_COMMUNICATION_THREAD, NULL);
    pthread_join(SEND_TO_SERVER_THREAD, NULL);
}



void *Switch_statement()
{

    while(1)
    {
    pthread_mutex_lock(&lock);
        while(UI_THREAD_RUNNING || SERVER_THREAD_RUNNING)
            pthread_cond_wait(&CONDITION_PIC, &lock);

        pthread_mutex_unlock(&lock);

        switch(userinput) 
        {
            case 0:         
                    printf("case0");
                    break;
            case 1:                                     //RETRIEVE ADC CASE
                    printf("case1");    
                    break;
            case 2:
                    printf("case2");
                    break;  
            case 3:                                     //RESET CASE
                    printf("case3");
                    break;                          //EXIT THE PROGRAM
            case 4:
                    printf("case4");
                    break;
            default:
                    printf("Your entry is not a valid option! Try again \n");                   
        }
    pthread_mutex_lock(&lock);
        PIC_THREAD_RUNNING = false;
        SERVER_THREAD_RUNNING = true;
    pthread_cond_signal(&CONDITION_SERVER);
        pthread_mutex_unlock(&lock);
    }
}

void *Server_function()
{
    while(1)
    {
        pthread_mutex_lock(&lock);
        while(PIC_THREAD_RUNNING || UI_THREAD_RUNNING)
            pthread_cond_wait(&CONDITION_SERVER, &lock);

        pthread_mutex_unlock(&lock);
        printf("SERVER FUNCTION");

    pthread_mutex_lock(&lock);
        SERVER_THREAD_RUNNING = false;
        UI_THREAD_RUNNING = true;
    pthread_cond_signal(&CONDITION_UI);
        pthread_mutex_unlock(&lock);
    }
}

void *User_choices()
{
    while (1)
    {
    pthread_mutex_lock(&lock);
        while (PIC_THREAD_RUNNING || SERVER_THREAD_RUNNING)
            pthread_cond_wait(&CONDITION_UI, &lock);

        pthread_mutex_unlock(&lock);
        printf("Type 0-4: ");
        scanf("%i", &userinput);
    pthread_mutex_lock(&lock);
        UI_THREAD_RUNNING = false;
        PIC_THREAD_RUNNING = true;
    pthread_cond_signal(&CONDITION_PIC);
        pthread_mutex_unlock(&lock);    
    }
}
Trever Wagenhals
  • 381
  • 5
  • 14
  • 1
    The worst situation is when things "appear to work". You are **still**, after being told *two times*, misusing `pthread_cond_wait()` in `Server_function()`. You are also passing an incompatible function pointer to `pthread_create()`. Did you even enable compiler warnings? – EOF Apr 14 '16 at 20:53
  • #EOF I had realized that I forgot to put pthread_mutex_lock at the top of the Server_function like the rest, is that wait you meant with using pthread_condit_wait() incorrectly? and how am I passing an incompatible function pointer? I will rerun now with all warnings as errors and see what it says. – Trever Wagenhals Apr 14 '16 at 21:18
  • The relevant prototype: `int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);`. This means that the `start_routine` must be a function, taking a `void *` argument and returning a `void*` value. You don't have to *use* either of them, but they are required. – EOF Apr 14 '16 at 21:26
  • So I did more reading and found that every example I saw passed an argument to the pthread instead of null like I did. Even though there's no passed parameter though I still need to make my functions of the void *function (void *) type, which is not what I did. Is that correct and what you were referencing? Also, I tried compiling with the -Werror command and nothing was raised. How come I can compile my program even though this is wrong? And inherently what type of problems does not doing this cause? Please let me know if what I'm inferring is wrong @EOF – Trever Wagenhals Apr 14 '16 at 22:17
  • The missing `void*`-argument is indeed what I was referring to. Now, as to why your compiler doesn't warn you: C is an old language, and one of its bad technical debts are old-style function declarations. Whenever you declare a function like this: `returntype functionname()`, you are telling the compiler not to check the number and types of the arguments. You should instead use function prototypes. If you want a function that doesn't take *any* arguments, the proper prototype is: `returntype functionname(void)`. Now your compiler will complain. – EOF Apr 14 '16 at 22:22
  • so, from what I'm seeing, I need the function to be of type `void * function(void *)`, but this causes a complaint as you mentioned. So, from what I read, I could create a wrapper function of the type `void * function(void *)` and then return my appropriate function to it like so `void * function_wrapper(void *){ return function();}` Is this a reasonable way to handle it? Otherwise, could I pass a variable even if I don't end up using the variable and be okay? The only other question you didn't answer is problems from not having the proper prototype then, even if it compiles and runs. @EOF – Trever Wagenhals Apr 15 '16 at 00:41
  • @TreverWagenhals it at-least looks to me you're trying to do something [like **this**](http://pastebin.com/TvGwYJNY). If the purpose is an exercise in thread juggling, that may help in getting you started. I *strongly* suggest getting a good book on pthreads. They're not trivial, and it is easy to make mistakes. Best of luck. – WhozCraig Apr 15 '16 at 05:52
  • @TreverWagenhals: The wrapper function should work. On the question of consequences for *not* using the correct function-prototype: C11 draft standard n1570: *6.5.2.2 Function calls 6 If the expression that denotes the called function has a type that does not include a prototype, [and] the number of arguments does not equal the number of parameters, the behavior is undefined.* In contrast, if the function *does* have a prototype, the compiler *must* give a warning if the number and type of function arguments doesn't match the call. – EOF Apr 15 '16 at 11:24