Thread synchronizing using shared variables and mutex in C











up vote
0
down vote

favorite












I'm trying to synchronize three pthreads using shared variables and mutex, such that they create the output: 123123123...
However, all I can think of is using while loop as shown in the code below.

Is it possible to make the code more elegant, without making the threads sleep and using while loop?



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

static pthread_mutex_t cs_mutex;
char p;
int q;

void* print(void *pParam)
{
char c = *(char*)pParam;
int i;

for (i = 0; i < 100; i++)
{
while(p!=c) sleep(0.2);
pthread_mutex_lock(&cs_mutex);
printf("%c", c);
fflush(stdout);
q=(q+1)%4;
if(q==0)q=1;
p=q+48;
pthread_mutex_unlock(&cs_mutex);
}

return 0;
}

int main(void)
{
pthread_t hPrint1;
pthread_t hPrint2;
pthread_t hPrint3;

pthread_mutex_init(&cs_mutex, NULL);

char c1 = '1';
char c2 = '2';
char c3 = '3';

p=c1;
q=1;

pthread_create(&hPrint1, NULL, print, (void*)&c1);
pthread_create(&hPrint2, NULL, print, (void*)&c2);
pthread_create(&hPrint3, NULL, print, (void*)&c3);

getchar();

pthread_mutex_destroy(&cs_mutex);

return 0;
}









share|improve this question




















  • 2




    You're probably looking for conditional wait.
    – paddy
    2 days ago















up vote
0
down vote

favorite












I'm trying to synchronize three pthreads using shared variables and mutex, such that they create the output: 123123123...
However, all I can think of is using while loop as shown in the code below.

Is it possible to make the code more elegant, without making the threads sleep and using while loop?



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

static pthread_mutex_t cs_mutex;
char p;
int q;

void* print(void *pParam)
{
char c = *(char*)pParam;
int i;

for (i = 0; i < 100; i++)
{
while(p!=c) sleep(0.2);
pthread_mutex_lock(&cs_mutex);
printf("%c", c);
fflush(stdout);
q=(q+1)%4;
if(q==0)q=1;
p=q+48;
pthread_mutex_unlock(&cs_mutex);
}

return 0;
}

int main(void)
{
pthread_t hPrint1;
pthread_t hPrint2;
pthread_t hPrint3;

pthread_mutex_init(&cs_mutex, NULL);

char c1 = '1';
char c2 = '2';
char c3 = '3';

p=c1;
q=1;

pthread_create(&hPrint1, NULL, print, (void*)&c1);
pthread_create(&hPrint2, NULL, print, (void*)&c2);
pthread_create(&hPrint3, NULL, print, (void*)&c3);

getchar();

pthread_mutex_destroy(&cs_mutex);

return 0;
}









share|improve this question




















  • 2




    You're probably looking for conditional wait.
    – paddy
    2 days ago













up vote
0
down vote

favorite









up vote
0
down vote

favorite











I'm trying to synchronize three pthreads using shared variables and mutex, such that they create the output: 123123123...
However, all I can think of is using while loop as shown in the code below.

Is it possible to make the code more elegant, without making the threads sleep and using while loop?



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

static pthread_mutex_t cs_mutex;
char p;
int q;

void* print(void *pParam)
{
char c = *(char*)pParam;
int i;

for (i = 0; i < 100; i++)
{
while(p!=c) sleep(0.2);
pthread_mutex_lock(&cs_mutex);
printf("%c", c);
fflush(stdout);
q=(q+1)%4;
if(q==0)q=1;
p=q+48;
pthread_mutex_unlock(&cs_mutex);
}

return 0;
}

int main(void)
{
pthread_t hPrint1;
pthread_t hPrint2;
pthread_t hPrint3;

pthread_mutex_init(&cs_mutex, NULL);

char c1 = '1';
char c2 = '2';
char c3 = '3';

p=c1;
q=1;

pthread_create(&hPrint1, NULL, print, (void*)&c1);
pthread_create(&hPrint2, NULL, print, (void*)&c2);
pthread_create(&hPrint3, NULL, print, (void*)&c3);

getchar();

pthread_mutex_destroy(&cs_mutex);

return 0;
}









share|improve this question















I'm trying to synchronize three pthreads using shared variables and mutex, such that they create the output: 123123123...
However, all I can think of is using while loop as shown in the code below.

Is it possible to make the code more elegant, without making the threads sleep and using while loop?



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

static pthread_mutex_t cs_mutex;
char p;
int q;

void* print(void *pParam)
{
char c = *(char*)pParam;
int i;

for (i = 0; i < 100; i++)
{
while(p!=c) sleep(0.2);
pthread_mutex_lock(&cs_mutex);
printf("%c", c);
fflush(stdout);
q=(q+1)%4;
if(q==0)q=1;
p=q+48;
pthread_mutex_unlock(&cs_mutex);
}

return 0;
}

int main(void)
{
pthread_t hPrint1;
pthread_t hPrint2;
pthread_t hPrint3;

pthread_mutex_init(&cs_mutex, NULL);

char c1 = '1';
char c2 = '2';
char c3 = '3';

p=c1;
q=1;

pthread_create(&hPrint1, NULL, print, (void*)&c1);
pthread_create(&hPrint2, NULL, print, (void*)&c2);
pthread_create(&hPrint3, NULL, print, (void*)&c3);

getchar();

pthread_mutex_destroy(&cs_mutex);

return 0;
}






c pthreads mutex






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 2 days ago

























asked 2 days ago









A6EE

114




114








  • 2




    You're probably looking for conditional wait.
    – paddy
    2 days ago














  • 2




    You're probably looking for conditional wait.
    – paddy
    2 days ago








2




2




You're probably looking for conditional wait.
– paddy
2 days ago




You're probably looking for conditional wait.
– paddy
2 days ago












1 Answer
1






active

oldest

votes

















up vote
0
down vote



accepted










When multiple threads try to acquire the mutex at the same time, any one of them can acquire it. So, if the "wrong" thread acquires the mutex, it must yield, somehow, so that the correct thread gets the mutex. In OP's code, the sleep(0.2) attempts to do this. (It is a busy wait, and does not work as intended, because the unistd.h sleep() takes an integer number of seconds as a parameter.)



A better option would be to use a mutex, a condition variable, and the sequence index as a shared variable. In pseudocode, each thread would then do:



Function Thread(mynumber, mychar):

Lock mutex

Loop:
Wait on condition variable
If index >= limit:
Signal on condition variable
Unlock mutex
Return
Else
If (index % mynumber == 0):
Output mychar
Signal on condition variable
Else:
Broadcast on condition variable
End If
End Loop
End Function


The way to pass more than one variable to the thread function is very similar to how you passed the character. Instead of a char, you just use a structure. For example:



struct work {
int mynumber; /* Thread number: 0, 1, 2 */
int mychar; /* Character to output: '1', '2', '3' */
};


You can declare struct work w[3]; as a global variable or in your main(), and initialize it using e.g.



    struct work w[3];
w[0].mynumber = 0; w[0].mychar = '1';
w[1].mynumber = 1; w[1].mychar = '2';
w[2].mynumber = 2; w[2].mychar = '3';


and refer to their address as say &(w[0]) (or equivalently just &w[0]).



In the thread function, you can use e.g.



void *worker(void *payload)
{
struct work *const w = payload;

/* w->mynumber is the number (0, 1, 2) of this thread,
w->mychar is the char ('1', '2', '3') to output */


Note that pthread_cond_signal() wakes up one thread already waiting on the condition variable, and pthread_cond_broadcast() wakes up all threads already waiting on the condition variable.



In the normal case, we only wake up one thread, to try and avoid the so-called thundering herd problem. It is not a real problem with just three threads, but I thought it is probably a good idea to introduce the concept here. Only if we find out the current thread is not the right one, do we wake up all the threads waiting on the condition variable.



If we only signaled on the condition variable, then it might be possible that two wrong threads would just alternate; that's why we really need that broadcast.






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53373653%2fthread-synchronizing-using-shared-variables-and-mutex-in-c%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    0
    down vote



    accepted










    When multiple threads try to acquire the mutex at the same time, any one of them can acquire it. So, if the "wrong" thread acquires the mutex, it must yield, somehow, so that the correct thread gets the mutex. In OP's code, the sleep(0.2) attempts to do this. (It is a busy wait, and does not work as intended, because the unistd.h sleep() takes an integer number of seconds as a parameter.)



    A better option would be to use a mutex, a condition variable, and the sequence index as a shared variable. In pseudocode, each thread would then do:



    Function Thread(mynumber, mychar):

    Lock mutex

    Loop:
    Wait on condition variable
    If index >= limit:
    Signal on condition variable
    Unlock mutex
    Return
    Else
    If (index % mynumber == 0):
    Output mychar
    Signal on condition variable
    Else:
    Broadcast on condition variable
    End If
    End Loop
    End Function


    The way to pass more than one variable to the thread function is very similar to how you passed the character. Instead of a char, you just use a structure. For example:



    struct work {
    int mynumber; /* Thread number: 0, 1, 2 */
    int mychar; /* Character to output: '1', '2', '3' */
    };


    You can declare struct work w[3]; as a global variable or in your main(), and initialize it using e.g.



        struct work w[3];
    w[0].mynumber = 0; w[0].mychar = '1';
    w[1].mynumber = 1; w[1].mychar = '2';
    w[2].mynumber = 2; w[2].mychar = '3';


    and refer to their address as say &(w[0]) (or equivalently just &w[0]).



    In the thread function, you can use e.g.



    void *worker(void *payload)
    {
    struct work *const w = payload;

    /* w->mynumber is the number (0, 1, 2) of this thread,
    w->mychar is the char ('1', '2', '3') to output */


    Note that pthread_cond_signal() wakes up one thread already waiting on the condition variable, and pthread_cond_broadcast() wakes up all threads already waiting on the condition variable.



    In the normal case, we only wake up one thread, to try and avoid the so-called thundering herd problem. It is not a real problem with just three threads, but I thought it is probably a good idea to introduce the concept here. Only if we find out the current thread is not the right one, do we wake up all the threads waiting on the condition variable.



    If we only signaled on the condition variable, then it might be possible that two wrong threads would just alternate; that's why we really need that broadcast.






    share|improve this answer

























      up vote
      0
      down vote



      accepted










      When multiple threads try to acquire the mutex at the same time, any one of them can acquire it. So, if the "wrong" thread acquires the mutex, it must yield, somehow, so that the correct thread gets the mutex. In OP's code, the sleep(0.2) attempts to do this. (It is a busy wait, and does not work as intended, because the unistd.h sleep() takes an integer number of seconds as a parameter.)



      A better option would be to use a mutex, a condition variable, and the sequence index as a shared variable. In pseudocode, each thread would then do:



      Function Thread(mynumber, mychar):

      Lock mutex

      Loop:
      Wait on condition variable
      If index >= limit:
      Signal on condition variable
      Unlock mutex
      Return
      Else
      If (index % mynumber == 0):
      Output mychar
      Signal on condition variable
      Else:
      Broadcast on condition variable
      End If
      End Loop
      End Function


      The way to pass more than one variable to the thread function is very similar to how you passed the character. Instead of a char, you just use a structure. For example:



      struct work {
      int mynumber; /* Thread number: 0, 1, 2 */
      int mychar; /* Character to output: '1', '2', '3' */
      };


      You can declare struct work w[3]; as a global variable or in your main(), and initialize it using e.g.



          struct work w[3];
      w[0].mynumber = 0; w[0].mychar = '1';
      w[1].mynumber = 1; w[1].mychar = '2';
      w[2].mynumber = 2; w[2].mychar = '3';


      and refer to their address as say &(w[0]) (or equivalently just &w[0]).



      In the thread function, you can use e.g.



      void *worker(void *payload)
      {
      struct work *const w = payload;

      /* w->mynumber is the number (0, 1, 2) of this thread,
      w->mychar is the char ('1', '2', '3') to output */


      Note that pthread_cond_signal() wakes up one thread already waiting on the condition variable, and pthread_cond_broadcast() wakes up all threads already waiting on the condition variable.



      In the normal case, we only wake up one thread, to try and avoid the so-called thundering herd problem. It is not a real problem with just three threads, but I thought it is probably a good idea to introduce the concept here. Only if we find out the current thread is not the right one, do we wake up all the threads waiting on the condition variable.



      If we only signaled on the condition variable, then it might be possible that two wrong threads would just alternate; that's why we really need that broadcast.






      share|improve this answer























        up vote
        0
        down vote



        accepted







        up vote
        0
        down vote



        accepted






        When multiple threads try to acquire the mutex at the same time, any one of them can acquire it. So, if the "wrong" thread acquires the mutex, it must yield, somehow, so that the correct thread gets the mutex. In OP's code, the sleep(0.2) attempts to do this. (It is a busy wait, and does not work as intended, because the unistd.h sleep() takes an integer number of seconds as a parameter.)



        A better option would be to use a mutex, a condition variable, and the sequence index as a shared variable. In pseudocode, each thread would then do:



        Function Thread(mynumber, mychar):

        Lock mutex

        Loop:
        Wait on condition variable
        If index >= limit:
        Signal on condition variable
        Unlock mutex
        Return
        Else
        If (index % mynumber == 0):
        Output mychar
        Signal on condition variable
        Else:
        Broadcast on condition variable
        End If
        End Loop
        End Function


        The way to pass more than one variable to the thread function is very similar to how you passed the character. Instead of a char, you just use a structure. For example:



        struct work {
        int mynumber; /* Thread number: 0, 1, 2 */
        int mychar; /* Character to output: '1', '2', '3' */
        };


        You can declare struct work w[3]; as a global variable or in your main(), and initialize it using e.g.



            struct work w[3];
        w[0].mynumber = 0; w[0].mychar = '1';
        w[1].mynumber = 1; w[1].mychar = '2';
        w[2].mynumber = 2; w[2].mychar = '3';


        and refer to their address as say &(w[0]) (or equivalently just &w[0]).



        In the thread function, you can use e.g.



        void *worker(void *payload)
        {
        struct work *const w = payload;

        /* w->mynumber is the number (0, 1, 2) of this thread,
        w->mychar is the char ('1', '2', '3') to output */


        Note that pthread_cond_signal() wakes up one thread already waiting on the condition variable, and pthread_cond_broadcast() wakes up all threads already waiting on the condition variable.



        In the normal case, we only wake up one thread, to try and avoid the so-called thundering herd problem. It is not a real problem with just three threads, but I thought it is probably a good idea to introduce the concept here. Only if we find out the current thread is not the right one, do we wake up all the threads waiting on the condition variable.



        If we only signaled on the condition variable, then it might be possible that two wrong threads would just alternate; that's why we really need that broadcast.






        share|improve this answer












        When multiple threads try to acquire the mutex at the same time, any one of them can acquire it. So, if the "wrong" thread acquires the mutex, it must yield, somehow, so that the correct thread gets the mutex. In OP's code, the sleep(0.2) attempts to do this. (It is a busy wait, and does not work as intended, because the unistd.h sleep() takes an integer number of seconds as a parameter.)



        A better option would be to use a mutex, a condition variable, and the sequence index as a shared variable. In pseudocode, each thread would then do:



        Function Thread(mynumber, mychar):

        Lock mutex

        Loop:
        Wait on condition variable
        If index >= limit:
        Signal on condition variable
        Unlock mutex
        Return
        Else
        If (index % mynumber == 0):
        Output mychar
        Signal on condition variable
        Else:
        Broadcast on condition variable
        End If
        End Loop
        End Function


        The way to pass more than one variable to the thread function is very similar to how you passed the character. Instead of a char, you just use a structure. For example:



        struct work {
        int mynumber; /* Thread number: 0, 1, 2 */
        int mychar; /* Character to output: '1', '2', '3' */
        };


        You can declare struct work w[3]; as a global variable or in your main(), and initialize it using e.g.



            struct work w[3];
        w[0].mynumber = 0; w[0].mychar = '1';
        w[1].mynumber = 1; w[1].mychar = '2';
        w[2].mynumber = 2; w[2].mychar = '3';


        and refer to their address as say &(w[0]) (or equivalently just &w[0]).



        In the thread function, you can use e.g.



        void *worker(void *payload)
        {
        struct work *const w = payload;

        /* w->mynumber is the number (0, 1, 2) of this thread,
        w->mychar is the char ('1', '2', '3') to output */


        Note that pthread_cond_signal() wakes up one thread already waiting on the condition variable, and pthread_cond_broadcast() wakes up all threads already waiting on the condition variable.



        In the normal case, we only wake up one thread, to try and avoid the so-called thundering herd problem. It is not a real problem with just three threads, but I thought it is probably a good idea to introduce the concept here. Only if we find out the current thread is not the right one, do we wake up all the threads waiting on the condition variable.



        If we only signaled on the condition variable, then it might be possible that two wrong threads would just alternate; that's why we really need that broadcast.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 2 days ago









        Nominal Animal

        27.9k33259




        27.9k33259






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53373653%2fthread-synchronizing-using-shared-variables-and-mutex-in-c%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

            Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

            A Topological Invariant for $pi_3(U(n))$