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;
}
c pthreads mutex
add a comment |
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;
}
c pthreads mutex
2
You're probably looking for conditional wait.
– paddy
2 days ago
add a comment |
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;
}
c pthreads mutex
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
c pthreads mutex
edited 2 days ago
asked 2 days ago
A6EE
114
114
2
You're probably looking for conditional wait.
– paddy
2 days ago
add a comment |
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
add a comment |
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.
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
answered 2 days ago
Nominal Animal
27.9k33259
27.9k33259
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
2
You're probably looking for conditional wait.
– paddy
2 days ago