Thread: Thread/mutex difficulty

  1. #16
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    Sorry last question.

    Where should pthread_mutex_init() be used?
    Last edited by erasm; 09-14-2009 at 07:46 AM.

  2. #17
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    I believe I compiled/executed my code.

    According to this either you can either

    Code:
    data.mutex_a = PTHREAD_MUTEX_INITIALIZER;
    //or
    pthread_mutex_init(&(data.mutex_a), NULL);
    The second is safer, as noted in the article

    In which line you get the error? Your error has nothing to do with threading though

  3. #18
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    There are no errors now.

    The tutorial i am doing now wants the parent thread to prompt the user to hit enter after the child prints the output. I supposedly have to use a second mutex. Why?

    I have browsed material on thread and mutexes but need clarification.

    If a mutex is used in a struct, would a pthread_mutex_lock call on a struct variable lock all contents of that struct's variables?

    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <pthread.h>
    
    
    typedef struct myStruct
    {
            pthread_mutex_t mutex_a;
            char buffer[100];
    } myStruct;
    
    void *print(void* data)
    {
            myStruct *d = (myStruct *)data;
            pthread_mutex_lock(&(d->mutex_a ));
            printf("%s\n", d->buffer);
            pthread_mutex_unlock(&(d->mutex_a ));
    }
    
    int main(void)
    {
            myStruct data;
            pthread_t thread;
    
            pthread_mutex_lock(&data.mutex_a);
            pthread_create(&thread, NULL, print, (void*)(&data));
            fgets(data.buffer, sizeof(data.buffer), stdin);
            pthread_mutex_unlock(&data.mutex_a);
            pthread_join(thread, NULL);
    }

  4. #19
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Look, in C you need to understand the logic behind the functions. Multi-threading is not that simple. It is just not enough for a program to work. You have to make sure it will always work, so I advise to give more thought on mutli-threading in general.

    When pthread_mutex_lock(&mutex) is called then there are two options:
    a) The mutex is locked. The thread waits until the mutex is unlocked to continue.
    b) The mutex is unlocked. The thread locks the mutex and continues its execution

    When pthread_mutex_unlock(&mutex) is called then the mutex is unlocked. So lets say you have thread A and B. Both have codes like:
    Code:
    //A
    printf("A1");
    printf("A2");
    
    //B
    printf("B1");
    printf("B2");
    The instructions will be executed randomly. The only thing you now is that:
    a) prinftf("A1") will be executed before printf("A2")
    b) prinft("B1") will be executed before prinft("B2)"
    In general the OS will decided to execute an instruction of either A or B

    For example they might be executed like this:
    Code:
    printf("B1");
    printf("A1");
    printf("A2");
    printf("B2");
    But you want either A to be executed first and B afterward or B executed first and A afterwards. You will use a mutex. Like this:
    Code:
    //A
    pthread_mutex_lock(&mutex);
    printf("A1");
    printf("A2");
    pthread_mutex_unlock(&mutex);
    
    //B
    pthread_mutex_lock(&mutex);
    printf("B1");
    printf("B2");
    pthread_mutex_unlock(&mutex);
    a)If pthread_mutex_lock is executed from A then the mutex will go in locked state and the rest of instructions in A will be executed
    b) If pthread_mutex_lock is now executed from B then B will wait because the mutex is locked. Only after pthread_mutex_unlock is called B will execute the rest of its instructions. So pthread_mutex_lock/unlock guarantees that the code in between these two functions() will be executed uninterrupted

    You can use multiple mutexes. Or you can reuse the same mutex. Every mutex can be either locked or unlocked. The functions lock/unlcok check for a specific mutex passed as a parameter

    Now, a mutex has nothing to do with a struct! The struct is used in pthread_create to pass a list of parameters. That is all the struct does.
    Last edited by C_ntua; 09-14-2009 at 01:49 PM.

  5. #20
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    Thanks for the reply. Just a few more questions.

    When you say the thread waits until the mutex is unlocked, do you mean the parent thread is waiting for the child thread to become unlocked?

    Should i use:

    if (pthread_mutex_destroy(&d->mutex_a) == 0)

    in the child thread to check if it is safe to return from this thread. If this condition is satisfied, how can i inform the parent thread that the child finished executing? Let me know if this is the wrong approach.
    Last edited by erasm; 09-14-2009 at 03:17 PM.

  6. #21
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    No. The child thread waits for the parent thread. In your last posted code this is what happens:
    a) The mutex is initialized and unlocked
    b) The parent thread calls lock(). The mutex is unlocked. So the parent thread locks it and continues its execution
    c) The parent thread calls pthread_create and creates the child thread.
    d) Now at this point both the parent and the child process run.
    e) There are a lot of possible combination of instructions here. The important thing is for fgets() in the parent thread to be executed before printf() in the child thread. That is guaranteed, because in order for printf() to be executed first the lock() in the child trehad will be called. But the mutex is "locked". So the child will wait for the parent.
    f) The parent will executed fgets() and eventually unlock().
    g) Now the child thread can execute its code, thus prinft().
    h) The parent thread won't terminate because it will wait for the child process to finish. This is done with pthread_join()

    Note that the pthread_mutex_unlock() in the child thread function is unecessary. It is a good practice to unlock the mutex you lock, but in this particular example it is not necessary


    No. That is not a good method at all, pthread_mutex_destroy isn't used for that purpose.

    There is no safety involved here. It is just the order of the instructions that are executed that you need to take care of. That is taken care of with a mutex.

    When I say "wait" I mean that the code stops executing at the point the pthread_mutex_lock() function is called. It waits there until an unlock() function is called from another thead. Then it continues executing and locks the mutex.

    To inform that parent thread that the child thread has finished executing you generally use pthread_join(). There are other ways as well, but this should be satisfying

    As for the tutorial you are using.
    The way you put it you don't have to do anything special. Just put the "prompt the user code" AFTER pthread_join(). If you want to make it more challenging, which is a really good idea to understand mutexes and multithreading is to make another thead that prompts the user. So you want:
    a) The parent thread to read data. As you do
    b) A second thread to print the data. As you do
    c) A third thread that prompts the user to press enter.
    HINT: Use two mutexes

  7. #22
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    Sorry, i made an error in my post earlier, the tutorial asks to make the parent prompt the user after printing, not after the child is finished. I was using pthread_join to check this but now i need to find a way to tell the parent the child has completed printing. Then inform the child when the parent receives a response to prompt. The hint does say to use 2 mutexes.

  8. #23
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    Why is this not printing the buffer? My understanding as commented in the code, is that once unlock is called on mutex_a in the parent, the suspended child should immediately begin executing which locks mutex_b. However i do not know where i could place another mutex_b so i can suspend the execution of the rest of the parent thread. At the moment, my attempt to suspend the parent seems to stop the child from printing the buffer. Is this because the lock call on mutex_b in the parent is executed before the child begins executing? How could i place the mutex_b to suspend the parent from executing until the child has printed?
    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <pthread.h>
    #include <unistd.h>
    #include <termios.h>
    
    typedef struct myStruct
    {
            pthread_mutex_t mutex_a;
            pthread_mutex_t mutex_b;
            char buffer[100];
    } myStruct;
    
    int getch(void)
    {
            int ch;
            struct termios oldt;
            struct termios newt;
            tcgetattr(STDIN_FILENO, &oldt);
            newt = oldt;
            newt.c_lflag &= ~(ICANON | ECHO);
            tcsetattr(STDIN_FILENO, TCSANOW, &newt);
            ch = getchar();
            tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
            return ch;
    }
    
    
    void *print(void* data)
    {
    
            myStruct *d = (myStruct *)data;
            pthread_mutex_lock(&(d->mutex_a ));
            pthread_mutex_lock(&(d->mutex_b ));
    
            printf("%s\n", d->buffer);
            pthread_mutex_unlock(&(d->mutex_a ));
            pthread_mutex_unlock(&(d->mutex_b ));
    
            if (pthread_mutex_destroy(&d->mutex_a) != 0)
            {
                    perror("cannot destroy mutex");
                    exit(EXIT_FAILURE);
            }
    }
    
    int main(void)
    {
            myStruct data;
            pthread_t thread;
            char c = ' ';
    
            if (pthread_mutex_init(&data.mutex_a, NULL) != 0)
            {
                    perror("cannot initialise mutex");
                    exit(EXIT_FAILURE);
            }
    
            pthread_mutex_lock(&data.mutex_a);
            pthread_create(&thread, NULL, print, (void*)(&data));
    
            fgets(data.buffer, sizeof(data.buffer), stdin);
    
            pthread_mutex_unlock(&data.mutex_a);
            //child thread execs which locks mutex_b
            //this thread will now be locked in suspension after the lock call, waiting to be unlocked by the child thread
            pthread_mutex_lock(&data.mutex_b);
    
            printf("press enter...\n");
            c = getch();
    
            if(c == 10)
            {
                    printf("you pressed enter\n");
            }
    
            pthread_join(thread, NULL);
    
    }

  9. #24
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    Solved.

    Swapped these around.
    Code:
    pthread_mutex_lock(&(d->mutex_a ));
    pthread_mutex_lock(&(d->mutex_b ));

  10. #25
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    You don't have it right. When unlock is called the child thread doesn't start automatically. The parent can continue being executed. You have to lock the parent thread first. You really don't need ptherad_mutex_destroy. Why destroy the mutex.

    Here is pseudo code with two mutexes:

    Code:
    //Parent
    lock(m1)
    lock(m2)
    create_thread ()
    fgets()
    unlock(m1)
    lock(m2)
    printf()
    
    //Child
    lock(m1)
    printf()
    unlock(m2)
    The parent goes first. It calls lock() for both mutexes. So both are locked. Then it creates a thread. The child thread for sure will wait, cause lock(m1) is called. So the parent thread continues. It does fgets() and then unlock(m1). Now both threads can continue executing. If child continues that is fine. But what if the parent continues? That is why you call lock(m2) on the parent. It cannot continue since m2 is locked. It will continue when unlock(m2) is called. Which means the child thread is done

    In your code the parent can actually continue executing and prompt for enter before the child prints. What is stopping it?

    Note, that as I said before your code might work. Because your computer will executed the instructions with a specific order. When you run the program again and again it is likely to follow the same order. But if you run the code on another computer, or another OS or change something else it might not work at all...

  11. #26
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    Quote Originally Posted by C_ntua View Post
    In your code the parent can actually continue executing and prompt for enter before the child prints. What is stopping it?

    Note, that as I said before your code might work. Because your computer will executed the instructions with a specific order. When you run the program again and again it is likely to follow the same order. But if you run the code on another computer, or another OS or change something else it might not work at all...
    You missed a lock on m2 from the child thread.

    //Parent
    lock(m1)
    lock(m2)
    create_thread ()
    fgets()
    unlock(m1)
    lock(m2)
    printf()

    //Child
    lock(m2) <-
    lock(m1)
    printf()
    unlock(m2)


    Wouldn't the lock on mutex_b stop the prompt section of the parent's code? mutex_b is only unlocked after the child prints.
    Last edited by erasm; 09-19-2009 at 10:29 PM.

  12. #27
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    Quote Originally Posted by erasm View Post
    How would i implement mutex with this code

    Would i pass buffer and mutex into a struct? If so, could someone show me how or reference a tutorial?

    Code:
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    
    
    
    
    void *print(void* string)
    {
            pthread_mutex_lock(&mutex);
            printf("%s\n", string);
            pthread_mutex_unlock(&mutex);
    }
    
    int main(void)
    {
    
            char buffer[100];
            
            pthread_t thread;
            pthread_create(&thread, NULL, print, (void*)buffer);
    
            fgets(buffer, sizeof(buffer), stdin);
    
            pthread_join(thread, NULL);
    
    }
    the mutex either has to have file scope or be passed by reference to the thread.

  13. #28
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    Now that i have written some semaphore functions i want to implement this program that used mutexes to achieve safe synchronization with these functions. But i am not sure how to approach this implemenation. I need pseudo code or a brief outline of the order of operations needed to synchronize two threads using semaphores to correctly print the buffer.

    Edit: from the mutex program, the problem is i don't see how a semaphore would stop printing of the buffer until the buffer is read while the threads run concurrently.

    Code:
    typedef struct semaphore
    {
        int count;
        pthread_cond_t got_request;
        pthread_mutex_t request_mutex;
    } semaphore;
    
    semaphore init_sem(semaphore *s)
    {
    	s->count = 0;
    	pthread_mutex_init(&(s.request_mutex, NULL));
            pthread_cond_init(&(s.got_request)
    }
    
    semaphore destroy_sem(semaphore *s)
    {
    	
    }
    
    void semWait(semaphore *s)
    {
    	pthread_mutex_lock(&(s->request_mutex));
            
    	if (s->count < 0)
            {
    	
    		pthread_cond_wait(&(s->got_request), &(s->request_mutex));
    		
            }
    	
    	s->count--;	
    	pthread_mutex_unlock(&(s->request_mutex));
    	
    }
    
    void semSignal(semaphore *s)
    {
    
            pthread_mutex_lock(&(s->request_mutex));
            s->count++;
    	
            if (s->count <= 0)
            {
    	
    	        pthread_cond_signal(&(s->got_request));		
    		
            }
    
            pthread_mutex_unlock(&(s->request_mutex));
    	
    }
    Last edited by erasm; 09-20-2009 at 10:25 PM.

  14. #29
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    In order to test my semaphore i have used this implementation

    So far the program will spawn a child which sleeps immediately and the parent reads buffer. Then when the child thread awakes it makes use of the semaphore and prints the buffer. From my understanding this displays how a semaphore avoids a deadlock. Now this problem is i cannot figure out how to use semaphores to get the order of operations correct (prompt from parent after printing buffer then exit). Is this possible with semaphores?

    Code:
    	semaphore *sem = (semaphore *)s;
    	sleep(10);
    	printf("child thread has awoken!");
    	semWait(sem);
    	//sem counter not < 0 so thread is granted access to buffer
    	//if counter was < 0 then thread would be suspended		        	
            printf("buffer = %s\n", sem->buffer);
    	semSignal(sem);
    
            printf("exiting from child...\n");                            <- Only occur after main thread prompts for enter
            exit(EXIT_SUCCESS);

    Code:
            semaphore sem;
    	pthread_t thread;
    	char c = ' ';
    	
    	init_sem(&sem);
    
    	pthread_create(&thread, NULL, semPrint, (void*)(&sem));
    	
    	//parent thread running
    	//child thread asleep
    	//sem counter = 1
    	semWait(&sem); //sem counter not < 0 so no block, counter - 1
    	fgets(sem.buffer, sizeof(sem.buffer), stdin);
    	semSignal(&sem); //sem now 0 so signal, counter + 1
    	//sem counter = 1
    	//child thread will awake soon
    
    	printf("press enter...\n");                                  <- Only prompt after child has printed

  15. #30
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Semaphores are like mutexes. The differense is that they have a count member. Nothing else. The count member is useful on some occasions.

    In your occasion, semephores can function exactly like mutexes. Instead of lock you put wait and instead of unlock you put signal.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 09-06-2009, 06:56 PM
  2. Replies: 4
    Last Post: 08-23-2009, 09:47 PM
  3. got difficulty on this
    By gtr_s15 in forum C++ Programming
    Replies: 4
    Last Post: 02-01-2006, 09:37 AM
  4. homework giving difficulty
    By jjj in forum C Programming
    Replies: 5
    Last Post: 09-13-2002, 06:35 PM
  5. Game difficulty
    By pdstatha in forum C++ Programming
    Replies: 5
    Last Post: 06-30-2002, 04:12 PM