Does sleep() interfere with scanf()? - c

I have two threads
xThread : Continuously Prints X on the console
inputThread: Gets input from the stdin
The continuous printing stops when the user enters 'C' or 'c'
#include<stdio.h>
#include<sys/select.h>
#include<pthread.h>
#define S sleep(0)
int read_c = 0;
pthread_mutex_t read_c_mutex = PTHREAD_MUTEX_INITIALIZER;
void* inputThread_fn(void* arg)
{
char inputChar;
while(1)
{
S;
printf("\nChecking input");
scanf("%c",&inputChar);
if(inputChar=='C' || inputChar == 'c')
{
pthread_mutex_trylock(&read_c_mutex); /*<--This must be _lock ?
because with the use of trylock even If i don't aquire a lock I go ahead and modify
the variable?*/
read_c = 1;
pthread_mutex_unlock(&read_c_mutex);
pthread_exit(NULL);
}
}
}
void* xThread_fn(void* arg)
{
while(1)
{
S;
pthread_mutex_trylock(&read_c_mutex);
if(!read_c)
printf(" X");
else
pthread_exit(NULL);
pthread_mutex_unlock(&read_c_mutex);
}
}
void* yThread_fn(void* arg)
{
while(1)
{
S;
pthread_mutex_trylock(&read_c_mutex);
if(!read_c)
printf(" Y");
else
pthread_exit(NULL);
pthread_mutex_unlock(&read_c_mutex);
}
}
int main()
{
pthread_t xThread,yThread,inputThread;
pthread_create(&xThread,NULL,xThread_fn,NULL);
pthread_create(&inputThread,NULL,inputThread_fn,NULL);
pthread_join(xThread,NULL);
pthread_join(inputThread,NULL);
return 0;
}
When I use sleep(1) the threads are spawned and [irrespective of which thread is started first] when the program reaches scanf in inputThread it halts for the user input and the code does not proceed until I enter an input.
When I execute the code with sleep(0), scanf does not halt for the input, it keeps printing 'X' until I enter 'C' or 'c'
Does sleep() interfere with scanf in someway?
Note: I am aware of select being used for non-blocking input. I have tried the same too and the code runs fine. I just want to know in the above case why inconsistent behaviour arises?
Update (Using trylock)
void* inputThread_fn(void* arg)
{
char inputChar;
while(1)
{
S;
scanf("%c",&inputChar);
if(inputChar=='C' || inputChar == 'c')
{
pthread_mutex_trylock(&read_c_mutex);
read_c = 1;
pthread_mutex_unlock(&read_c_mutex);
pthread_exit(NULL);
}
}
}
void* xThread_fn(void* arg)
{
while(1)
{
S;
pthread_mutex_trylock(&read_c_mutex);
if(!read_c)
{
pthread_mutex_unlock(&read_c_mutex);
printf(" X");
}
else
{
pthread_mutex_unlock(&read_c_mutex);
pthread_exit(NULL);
}
fflush(stdout);
}
}
void* yThread_fn(void* arg)
{
while(1)
{
S;
pthread_mutex_trylock(&read_c_mutex);
if(!read_c)
{
pthread_mutex_unlock(&read_c_mutex);
printf(" Z");
fflush(stdout);
}
else
{
pthread_mutex_unlock(&read_c_mutex);
pthread_exit(NULL);
}
}
}

The reason you don't see output is because you're not flushing the buffer.
The reason you don't need to flush the buffer with sleep(0) is because the writer thread writes so much data that the buffer fills up and is automatically flushed.
#define SLEEP_TIME 1
void* xThread_fn(void* arg)
{
while (1) {
sleep(SLEEP_TIME);
pthread_mutex_lock(&read_c_mutex);
if (read_c) {
pthread_mutex_unlock(&read_c_mutex);
return NULL;
}
pthread_mutex_unlock(&read_c_mutex);
printf(" X");
fflush(stdout); // <-- necessary
}
}
Don't use pthread_mutex_trylock()
Don't use pthread_mutex_trylock() here. It's wrong.
The difference between lock() and trylock() is that lock() will always succeed1 but trylock() will sometimes fail. That's why it's called "try".
Since trylock() sometimes fails, you have to handle the case where it failed. Your code doesn't handle the case: it simply plows forward, pretending it acquired the lock. So, suppose trylock() doesn't lock the mutex. What happens?
pthread_mutex_trylock(&read_c_mutex); // Might fail (i.e., not lock the mutex)
read_c = 1; // Modifying shared state (Wrong!)
pthread_mutex_unlock(&read_c_mutex); // Unlocking a mutex (Wrong!)
Then there's the question of how the code should handle trylock() failing. If you can't answer this question, then the default answer is "use lock()".
In the reader thread, you can't use trylock() because you have to lock the mutex:
int r = pthread_mutex_trylock(&read_c_mutex);
if (r != 0) {
// Uh... what are we supposed to do here? Try again?
} else {
read_c = 1;
pthread_mutex_unlock(&read_c_mutex);
}
In the writer thread, there's no point in using trylock():
int r = pthread_mutex_trylock(&read_c_mutex);
if (r != 0) {
// Okay, just try again next loop...
} else {
if (read_c) {
pthread_mutex_unlock(&read_c_mutex);
pthread_exit(NULL);
} else {
pthread_mutex_unlock(&read_c_mutex);
}
}
However, this is entirely pointless. The only reason trylock() will fail in the writer thread is if the reader thread owns the lock, which only happens if it is currently in the process of setting read_c = 1;. So you might as well wait for it to finish, since you know you're going to exit anyway (why write more output after you know that the user has signaled your program to stop?)
Just use lock(). You'll use lock() 99% of the time, and trylock() is for the other 1%.
1: The lock() function can fail, but this usually means you've misused the mutex.
Misconceptions about lock() and trylock()
You said this about trylock():
If i have another thread accessing the variable read_input then will it be appropriate to use it?
I think there is a very fundamental misunderstanding here about the nature of mutexes. If another thread weren't accessing the variable at the same time, then you wouldn't need a mutex at all.
Suppose you're doing important work at the office, and you need to use the photocopier. Only one person can use the photocopier at a time. You go to the photocopier and someone's already using it.
If you wait in line until it's your turn, then that's lock().
If you give up and go back to your desk, then that's trylock(). (Your program actually ignores the return code for trylock(), so you basically start mashing buttons on the photocopier even if someone else is using it.)
Now imagine that it takes one minute to use the photocopier, only two people ever use the photocopier, and they only use the photocopier once every twenty years.
If you use lock(), then you wait in line for at most one minute before using the photocopier.
If you use trylock(), then you give up and go back to your desk and wait twenty years before trying the photocopier again.
It doesn't make any sense to use trylock(), does it? Are your threads so impatient that they can't spend even one minute in line once every twenty years?
Now your boss comes down and said, "Where is that report I asked you to photocopy?" And you say, "Well, I went to the photocopier six years ago but someone was using it."
The numbers (one minute every twenty years) are based on Latency Numbers Every Programmer Should Know, where it notes that locking/unlocking a mutex is about 25ns. So if we pretend that it takes one minute to lock and then unlock a mutex, then sleep(1) causes the thread to wait for twenty years.

Related

C - sleep() in threads gives problems

sleep() function gives me problem in a program.
I have declared only one mutex, one condition variable and one global variable:
pthread_mutex_t mutex;
pthread_cond_t something1;
int protected = 1;
After initializing them, and creating the 2 threads inside the main with pthread_create, i write this:
void *Thread(void *arg)
{
while(1){
pthread_mutex_lock(&mutex);
while(protected == 0){
pthread_cond_wait(&something1, &mutex);
}
printf("aaa");
sleep(2);
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
void *Thread2(void *arg){
while(1){
pthread_mutex_lock(&mutex);
while(protected == 1){
pthread_cond_wait(&something1, &mutex);
}
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
This should just print "aaa" in loop forever, and this works if I remove the sleep(2).
If I leave it, the program starts, stays alive, but it prints nothing.
Any ideas why this happens?
printf is line buffered, meaning it won't flush the buffer to screen until it reaches a newline "\n", or when the buffer is full. When you don't sleep, the buffer fills up quickly and prints to screen when it gets full, but when you do sleep it will take a long time for the buffer to fill, and so you never see anything on screen. Try changing that to printf("aaa\n");, or add an fflush(stdout); after the printf. See more information here: Why does printf not flush after the call unless a newline is in the format string?

IPC_NOWAIT semop() Buffer SysV Processes

I'm really in trouble with this piece of code.
I have a buffer and a method Produce() which should be Non Blocking,this means that when many processes try to Produce() all of them should return/or fail except one process.
I read that in man semop(),when we use IPC_NOWAIT process should fails if the semaphor is already in use. But What Does it mean fails? It returns something? It does an Exit() ?
I really don't know what happens.
In my code, sometimes I found 2 messages in the buffer and sometimes 1.
Since I'm using IPC_NOWAIT I should have at the end just 1 single message in the buffer because other processes should fail because the have been started together!
Here is the Produce() code:
msg_t* put_non_bloccante(buffer_t* buffer, msg_t* msg){
...
struct sembuf sb;
sb.sem_flg=IPC_NOWAIT;
int x=0;
sb.sem_num=VUOTE; sb.sem_op=-1;
if ((x=semop(buffer->semid, &sb,1))<0) {
printf("\n DENTROOOO DOWN%d VUOTE \n",x);/* down(VUOTE) */
perror("semop() producer down(VUOTE)");
exit(-9);
}
sb.sem_num=USO_D; sb.sem_op=-1;
if ((x=semop(buffer->semid, &sb,1))<0) { /* down(USO_D) */
printf("\n DENTROOOO DO%dWN USO D \n",x);
perror("semop() producer down(USO_D)");
exit(-10);
}
if((buffer->msg_presenti)< (buffer->size)){
/*HERE DROP THE MESSAGE IN THE BUFFER IF IS NOT FULL*/
}
sb.sem_num=USO_D; sb.sem_op= 1;
if (semop(buffer->semid, &sb,1)<0) { /* up(USO_D) */
printf("\n DENTROOOO UP USO D \n");
perror("semop() producer up(USO_D)");
exit(-11);
}
sb.sem_num=PIENE; sb.sem_op= 1;
if (semop(buffer->semid, &sb,1)<0) {
printf("\n DENTROOOO UP PIENE \n");/* up(PIENE) */
perror("semop() producer up(PIENE)");
exit(-12);
}
int delay;
delay = (int)(random() % 5 ) / 2 + 1;
sleep(delay);
}
shmdt(buffer);
shmdt(sa);
shmdt(array_msg); */
return msg;
}
Here my simple CUNIT test:
void test_bufferVuoto_3P_NonBlocking_Concurrently(void)
{
pid_t pid=-1;
msg_t* msg = msg_init_string("ciao");
pid_t cons_pid[3];
buffer_t* b=buffer_init(3);
int k;
for(k=0;k<3 && pid!=0;k++) {
pid = cons_pid[k]=fork();
}
switch(pid){
case -1:
printf("error fork()");
exit(-5);
break;
case 0:
buffer_attach(b->bufferid);
msg_attach(msg->msg_id);
put_non_bloccante(b,msg);
msg_deattach(msg);
buffer_deattach(b);
sleep(17);
exit(-5);
}
sleep(12);
int j=0;
for(j=0; j<3; j++) {
kill(cons_pid[j],SIGKILL); // ... and Kill processes
wait(NULL);
}
CU_ASSERT_EQUAL(b->msg_presenti,1);
CU_ASSERT(0==strcmp("ciao", (b->array_msg[0])->content) );
msg_destroy_string(msg);
buffer_destroy(b);
return;
}
I also read a BUG In the Man of SemOP() and IPC_NOWAIT I don'know if is related to this:
*This is however undesirable since it could force
process termination to block for arbitrarily long periods. Another
possibility is that such semaphore adjustments could be ignored alto‐
gether (somewhat analogously to failing when IPC_NOWAIT is specified
for a semaphore operation). Linux adopts a third approach: decreasing
the semaphore value as far as possible (i.e., to zero) and allowing
process termination to proceed immediately.
In kernels 2.6.x, x <= 10, there is a bug that in some circumstances
prevents a process that is waiting for a semaphore value to become zero
from being woken up when the value does actually become zero. This bug
is fixed in kernel 2.6.11.*
As far as I can see the semaphores are doing what you ask but your concept of what should be happening is a little skewed.
If you use IPC_NOWAIT and the process can't acquire the semaphore then it will immediately return with -1 and errno == EAGAIN. Normally you would use this time to do something else and try again later. You are immediately exiting the process, possibly while holding one or more of the semaphores.
Worse yet it looks like you have at least 3 semaphores going. You decrement VUOTE and USO_D, do something, and then increment USO_D and PIENE leaving VUOTE locked. Is that a typo, a mistake, or my misunderstanding?
Overall your expectations of what should happen are wrong. It is entirely possible for your code to end up with 1,2 or 3 messages. (And possibly 0 if bailing out while holding a semaphore.) In other words, depending on how they are scheduled by the OS all 3 of your processes can acquire the semaphore and succeed or maybe just one or two. It is indeterminate.
If it is really your intention that one and only one process can succeed then just initialize a semaphore to 1 and never increment it. The first process to acquire it will get to proceed and the rest will fail because it will never again allow anything else through.
Edit
if ((x = semop(buffer->semid, &sb, 1)) < 0)
{
printf("\n DENTROOOO DOWN%d VUOTE \n", x); /* down(VUOTE) */
perror("semop() producer down(VUOTE)");
exit( -9);
}
Here the semop call returns immediately setting x to -1 and errno to EAGAIN if it can't get the lock. You are coding it to just exit the process. You can code the condition to do something else.
if ((x = semop(buffer->semid, &sb, 1)) < 0)
{
if (errno == EAGAIN)
return NULL; //OR WHATEVER you think appropriate
else
{ //some other failure that's not EAGAIN
printf("\n DENTROOOO DOWN%d VUOTE \n", x); /* down(VUOTE) */
perror("semop() producer down(VUOTE)");
exit( -9);
}
}
//ELSE you got the lock
The processes don't know about each other except (indirectly) through the use of the semaphores. Each of them is going to execute this code. Some will succeed and some won't.
The reason this doesn't work with IPC_NOWAIT is because it is entirely possible each process won't have to wait for the lock. Depending on how they are scheduled one might get the lock and execute, then the next and the next. Or some will and some won't. It is impossible to predict.

How to stop a running pthread thread?

How can I exit or stop a thread immediately?
How can I make it stop immediately when the user enters an answer?
I want it to reset for every question.
Here's my code where threading is involved
int q1() {
int timer_start;
char ans[] = "lol";
char user_ans[50];
timer_start = pthread_create( &xtimer,NULL,(void*)timer_func,(void*)NULL);
printf("What is the capital city of Peru?\n");
while(limit){
scanf("%s",user_ans);
if(limit)
{
if(!strcmp(user_ans, ans))
{
// printf("YAY!\n");
score++;
// q2();
}
else
{
game_over();
}
}
}
}
You can simply call pthread_cancel on that thread to exit it. And you can send SIGSTOP/SIGCONT signal via pthread_kill to stop/restart it.
But if all you want is a timer, why must you thread?
Based on your code I can give a simple answer:
In this case do not use threads at all.
You do not need them. Store the start time, let the user answer, check the time again after user gives an answer.
{
time_t startTimeSec = time(NULL);
// answering
time_t endTimeSec = time(NULL);
time_t timeTakenSec = endTime-startTime;
if (timeTaken > 10) {
// do your thing
}
}
To answer your question:
You should use a mutex-protected or volatile variable to asynchronously communicate between threads. Set that variable from one thread and check it in another. Then reset its value and repeat. A simple snippet:
int stopIssued = 0;
pthread_mutex_t stopMutex;
int getStopIssued(void) {
int ret = 0;
pthread_mutex_lock(&stopMutex);
ret = stopIssued;
pthread_mutex_unlock(&stopMutex);
return ret;
}
void setStopIssued(int val) {
pthread_mutex_lock(&stopMutex);
stopIssued = val;
pthread_mutex_unlock(&stopMutex);
}
Using pthread_cancel() is an option, but I would not suggest doing it. You will have to check the threads state after this call returns, since pthread_cancel() does not wait for the actual thread stop. And, which to me is even more important, I consider using it ugly.
Using methods to stop a thread is a brute way.
You should rather politely ask the thread to stop by signalling.
Thereby the thread will have an option to tidy after itself e.g. if it has allocated memory, which it will not have any opportunity to do if the thread is cancelled.
The method is relatively simple and comprises no OS signalling:
define a thread state variable or structure outside the thread. Point to it at the pthread_create and dereference the state variable in the thread.
int thread_state = 0; // 0: normal, -1: stop thread, 1: do something
static void *thread_1 (void *arg)
{
int* pthread_state = arg;
... // initialize the thread locals
while(1)
{
switch( *pthread_state )
{
case 0: // normal thread loop
...
break;
case -1:
... // tidy or whatever is necessary
pthread_exit(0); // exit the thread signalling normal return
break;
case 1: //
... // do something special
break;
}
}
}
pthread_create (&t_1, NULL, thread_1, (void*)&thread_state);
...
thread_state = -1; // signal to the thread to stop
// maybe use pthread_exit(0) to exit main.
// this will leave the threads running until they have finished tidy etc.
It is even possible to communicate with the thread using a structure provided that it is simple 'atomic' variables or a simple handshake mechanism is established. Otherwise it may be necessary to use mutex.
Use pthread_join to wait for threads to terminate.
#Naruil's suggestion to call pthread_cancel() is pretty much the best solution i found, but it won't work if you didn't do the following things.
According to the man-page of pthread_cancel the pthread_cancelibility depend on two thing
thread_cancel_state.
thread_cancel_type.
thread_cancel_state is PTHREAD_CANCEL_ENABLE by default, so our main concern is about the thread_cancel_type, it's default value is type PTHREAD_CANCEL_DEFFERED but we need PTHREAD_CANCEL_ASYNCHRONOUS to set on that thread, which we wan't to cancel.
Following an example given::
#include <stdio.h>
#include <pthread.h>
void *thread_runner(void* arg)
{
//catch the pthread_object as argument
pthread_t obj = *((pthread_t*)arg);
//ENABLING THE CANCEL FUNCTIONALITY
int prevType;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &prevType);
int i=0;
for( ; i < 11 ; i++)//1 - > 10
{
if(i == 5)
pthread_cancel(obj);
else
printf("count -- %d", i);
}
printf("done");
}
int main(int argc, char *argv[])
{
pthread_t obj;
pthread_create(&obj, NULL, thread_runner, (void*)&obj);
pthread_join(obj, NULL);
return 0;
}
run it using gcc filename.c -lpthread and output the following::
count -- 0
count -- 1
count -- 2
count -- 3
count -- 4
note that the done is never printed because the thread was canceled when the i became 5 & the running thread was canceled. Special thanks #Naruil for the "pthread_cancel" suggestion.

How can I wait for any/all pthreads to complete?

I just want my main thread to wait for any and all my (p)threads to complete before exiting.
The threads come and go a lot for different reasons, and I really don't want to keep track of all of them - I just want to know when they're all gone.
wait() does this for child processes, returning ECHILD when there are no children left, however wait does not (appear to work with) (p)threads.
I really don't want to go through the trouble of keeping a list of every single outstanding thread (as they come and go), then having to call pthread_join on each.
As there a quick-and-dirty way to do this?
Do you want your main thread to do anything in particular after all the threads have completed?
If not, you can have your main thread simply call pthread_exit() instead of returning (or calling exit()).
If main() returns it implicitly calls (or behaves as if it called) exit(), which will terminate the process. However, if main() calls pthread_exit() instead of returning, that implicit call to exit() doesn't occur and the process won't immediately end - it'll end when all threads have terminated.
http://pubs.opengroup.org/onlinepubs/007908799/xsh/pthread_exit.html
Can't get too much quick-n-dirtier.
Here's a small example program that will let you see the difference. Pass -DUSE_PTHREAD_EXIT to the compiler to see the process wait for all threads to finish. Compile without that macro defined to see the process stop threads in their tracks.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
static
void sleep(int ms)
{
struct timespec waittime;
waittime.tv_sec = (ms / 1000);
ms = ms % 1000;
waittime.tv_nsec = ms * 1000 * 1000;
nanosleep( &waittime, NULL);
}
void* threadfunc( void* c)
{
int id = (int) c;
int i = 0;
for (i = 0 ; i < 12; ++i) {
printf( "thread %d, iteration %d\n", id, i);
sleep(10);
}
return 0;
}
int main()
{
int i = 4;
for (; i; --i) {
pthread_t* tcb = malloc( sizeof(*tcb));
pthread_create( tcb, NULL, threadfunc, (void*) i);
}
sleep(40);
#ifdef USE_PTHREAD_EXIT
pthread_exit(0);
#endif
return 0;
}
The proper way is to keep track of all of your pthread_id's, but you asked for a quick and dirty way so here it is. Basically:
just keep a total count of running threads,
increment it in the main loop before calling pthread_create,
decrement the thread count as each thread finishes.
Then sleep at the end of the main process until the count returns to 0.
.
volatile int running_threads = 0;
pthread_mutex_t running_mutex = PTHREAD_MUTEX_INITIALIZER;
void * threadStart()
{
// do the thread work
pthread_mutex_lock(&running_mutex);
running_threads--;
pthread_mutex_unlock(&running_mutex);
}
int main()
{
for (i = 0; i < num_threads;i++)
{
pthread_mutex_lock(&running_mutex);
running_threads++;
pthread_mutex_unlock(&running_mutex);
// launch thread
}
while (running_threads > 0)
{
sleep(1);
}
}
If you don't want to keep track of your threads then you can detach the threads so you don't have to care about them, but in order to tell when they are finished you will have to go a bit further.
One trick would be to keep a list (linked list, array, whatever) of the threads' statuses. When a thread starts it sets its status in the array to something like THREAD_STATUS_RUNNING and just before it ends it updates its status to something like THREAD_STATUS_STOPPED. Then when you want to check if all threads have stopped you can just iterate over this array and check all the statuses.
Don't forget though that if you do something like this, you will need to control access to the array so that only one thread can access (read and write) it at a time, so you'll need to use a mutex on it.
you could keep a list all your thread ids and then do pthread_join on each one,
of course you will need a mutex to control access to the thread id list. you will
also need some kind of list that can be modified while being iterated on, maybe a std::set<pthread_t>?
int main() {
pthread_mutex_lock(&mutex);
void *data;
for(threadId in threadIdList) {
pthread_mutex_unlock(&mutex);
pthread_join(threadId, &data);
pthread_mutex_lock(&mutex);
}
printf("All threads completed.\n");
}
// called by any thread to create another
void CreateThread()
{
pthread_t id;
pthread_mutex_lock(&mutex);
pthread_create(&id, NULL, ThreadInit, &id); // pass the id so the thread can use it with to remove itself
threadIdList.add(id);
pthread_mutex_unlock(&mutex);
}
// called by each thread before it dies
void RemoveThread(pthread_t& id)
{
pthread_mutex_lock(&mutex);
threadIdList.remove(id);
pthread_mutex_unlock(&mutex);
}
Thanks all for the great answers! There has been a lot of talk about using memory barriers etc - so I figured I'd post an answer that properly showed them used for this.
#define NUM_THREADS 5
unsigned int thread_count;
void *threadfunc(void *arg) {
printf("Thread %p running\n",arg);
sleep(3);
printf("Thread %p exiting\n",arg);
__sync_fetch_and_sub(&thread_count,1);
return 0L;
}
int main() {
int i;
pthread_t thread[NUM_THREADS];
thread_count=NUM_THREADS;
for (i=0;i<NUM_THREADS;i++) {
pthread_create(&thread[i],0L,threadfunc,&thread[i]);
}
do {
__sync_synchronize();
} while (thread_count);
printf("All threads done\n");
}
Note that the __sync macros are "non-standard" GCC internal macros. LLVM supports these too - but if your using another compiler, you may have to do something different.
Another big thing to note is: Why would you burn an entire core, or waste "half" of a CPU spinning in a tight poll-loop just waiting for others to finish - when you could easily put it to work? The following mod uses the initial thread to run one of the workers, then wait for the others to complete:
thread_count=NUM_THREADS;
for (i=1;i<NUM_THREADS;i++) {
pthread_create(&thread[i],0L,threadfunc,&thread[i]);
}
threadfunc(&thread[0]);
do {
__sync_synchronize();
} while (thread_count);
printf("All threads done\n");
}
Note that we start creating the threads starting at "1" instead of "0", then directly run "thread 0" inline, waiting for all threads to complete after it's done. We pass &thread[0] to it for consistency (even though it's meaningless here), though in reality you'd probably pass your own variables/context.

Implementing producers/consumers using mutex

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#define WORK_SIZE 1024
pthread_mutex_t work_mutex;
char work_area[WORK_SIZE];
void *thread_start(void *);
int main() {
pthread_t a_thread;
pthread_mutex_init(&work_mutex,NULL);
pthread_create(&a_thread,NULL,thread_start,NULL);
while(1)
{
pthread_mutex_lock(&work_mutex);
printf("Enter some text\n");
fgets(work_area, WORK_SIZE, stdin);
pthread_mutex_unlock(&work_mutex);
}
return 0;
}
void *thread_start(void *arg)
{
sleep(1);
while(1)
{
pthread_mutex_lock(&work_mutex);
printf("You enetered %d char",strlen(work_area));
pthread_mutex_unlock(&work_mutex);
}
}
When I execute the program, after releasing of the mutex lock in main thread, it again aquires the lock, everytime, before the second thread could aquire the lock. I was expecting that once the main thread would release the lock, the second thread which is already blocked would aquire the lock and start execution before the main.
To be more clear, I am getting such type of output :-
Enter some text
qwerty
Enter some text
asdaf
Enter some text
jkdf
Enter some text
It just seems that way to you. You lock before doing data entry in main which is going to be orders of magnitude greater than what it take to output the line. In all that time the other thread will do nothing but block. Your main is going to release the lock and microseconds later acquire it again.
If you do this long enough - maybe thousands of times - you will see it work. But it would be better to just copy the input line in main to a queue or some other piece of memory protect by the lock. Then the other thread would have a chance to get at it.
EDIT:
The general idea is this. My code additions are terrible but should work well enough for illustration.
int main()
{
pthread_t a_thread;
pthread_mutex_init(&work_mutex, NULL);
pthread_create(&a_thread, NULL, thread_start, NULL);
memset(work_area, '\0', sizeof(work_area));
char input[WORK_SIZE - 1];
while (1)
{
printf("Enter some text\n");
fgets(input, WORK_SIZE, stdin);
pthread_mutex_lock(&work_mutex);
strcpy(work_area, input);
pthread_mutex_unlock(&work_mutex);
}
return 0;
}
void *thread_start(void *arg)
{
sleep(1);
while (1)
{
pthread_mutex_lock(&work_mutex);
if (work_area[0] != '\0')
{
printf("You enetered %d char\n", strlen(work_area));
work_area[0] = '\0';
}
pthread_mutex_unlock(&work_mutex);
}
}
Putting asside the suggestion to use a semaphore, I think that the reason for the behaviour that you are observing is as follows.
Until the pthread_mutex_lock in thread_start is called, the loop in main won't be blocked.
Therefore, the only time that thread_start's loop will get a chance to call pthread_mutex_lock is when the time slice of the thread executing main expires
The chances of that time slice expiry occuring while the lock is released is miniscule. This is because the main thread will probably have a fresh time slice when it wakes from the blocked state while it waited for the ENTER key.
Note, this explanation assumes a single core. But even on a multicore system the thread_start thread is only going to be scheduled when another thread's time slice runs out. The chances of that happening while main's thread isn't holding the lock is small.
One possible test for my above hypothesis would be to call pthread_yield after releasing the lock. You'll probably want to do that in both threads. Even then I don't think it will GUARANTEE a thread switch every time.
You may want to create and initialise a semaphore and then wait in the 2nd thread for the main function to signal a event when a input is fed to it.
Check conditional wait and semaphores.
The second thread doesnt know what event is generated in the main thread. For your reference.
After reading the comments given by torak, I changed the code. Now it is working fine as expected.
[root#localhost threads]# diff -Nurp mutex.c mutex_modified.c
--- mutex.c 2010-07-09 19:50:51.000000000 +0530
+++ mutex_modified.c 2010-07-09 19:50:35.000000000 +0530
## -18,6 +18,7 ## pthread_mutex_lock(&work_mutex);
printf("Enter some text\n");
fgets(work_area, WORK_SIZE, stdin);
pthread_mutex_unlock(&work_mutex);
+sleep(1);
}
return 0;
}
## -30,5 +31,6 ## while(1)
pthread_mutex_lock(&work_mutex);
printf("You enetered %d char",strlen(work_area));
pthread_mutex_unlock(&work_mutex);
+sleep(1);
}
}
It is still very confusing though. Although it was a test program, what should one do to avoid such kind of situation while coding a real application?
Here's a slightly more awkward solution that's guaranteed to work: #include
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#define WORK_SIZE 1024
pthread_mutex_t work_mutex;
char input_area[WORK_SIZE];
char work_area[WORK_SIZE];
void *thread_start(void *);
int main()
{
pthread_t a_thread;
pthread_mutex_init(&work_mutex,NULL);
work_area[0] = 0;
pthread_create(&a_thread,NULL,thread_start,NULL);
while(1) {
printf("Enter some text\n");
fgets(input_area, WORK_SIZE, stdin);
pthread_mutex_lock(&work_mutex);
while (work_area[0] != 0) {
pthread_mutex_unlock(&work_mutex);
sleep(1);
pthread_mutex_lock(&work_mutex);
}
memcpy(work_area, input_area, WORK_SIZE);
pthread_mutex_unlock(&work_mutex);
}
return 0;
}
void *thread_start(void *arg)
{
while(1)
{
pthread_mutex_lock(&work_mutex);
if (work_area[0] > 0) {
printf("you enetered %d char\n",strlen(work_area));
work_area[0] = 0;
pthread_mutex_unlock(&work_mutex);
} else {
pthread_mutex_unlock(&work_mutex);
sleep(1);
}
}
}
Note that because POSIX mutex locks are thread-specific, the consumer thread can't wait on a signal from the producer thread, so here it just wakes up every second to check for new data. Similarly, if the producer needs to put something in queue and the work area is full, it waits by seconds until the consumer gets around to emptying the buffer. You could get rid of some delays by using pthread_yield instead of sleep, but then your threads will 'busy-wait', consuming lots of CPU to check again and again for their condition to be met
Note that if you want it to print a line for 0-character entries you could add a separate bool indicating whether there's new data in the queue.
#torax
*"Note, this explanation assumes a single core. But even on a multicore system the thread_start thread is only going to be scheduled when another thread's time slice runs out"*
I think this is not true, the main thread and the thread_start can be scheduled parallely on both cores

Resources