In your scanf task, which is waiting for data entry, it can serve as a “natural synchronizer” and then the program is somewhat simplified.
char password[] = "password"; char str[30]; pthread_cond_t wake_up; pthread_mutex_t mut; void *enter_pass(void *a) { while(1) { printf("Enter password:\n"); scanf("%s", str); pthread_mutex_lock(&mut); pthread_cond_signal(&wake_up); pthread_mutex_unlock(&mut); } } void *check_pass(void *a) { while(1) { pthread_mutex_lock(&mut); pthread_cond_wait(&wake_up, &mut); pthread_mutex_unlock(&mut); if(!strcmp(str , password)) { printf("true\n"); exit(EXIT_SUCCESS); } printf("Wrong password, try another\n"); } } int main(void) { pthread_t thread1, thread2; pthread_mutex_init(&mut, NULL); pthread_cond_init (&wake_up, NULL); pthread_create(&thread1, NULL, enter_pass, 0); pthread_create(&thread2, NULL, check_pass, 0); pthread_join(thread1, NULL); pthread_join(thread2, NULL); }
Now only one mutex and one condition variable are needed.
However, it is impossible to rely on such "synchronization" of interaction between threads. @VladD in his response showed how to synchronize the start of work streams from main.
And here is another way to "handshake" without external synchronization. Add a couple of variables and a simple function.
int checker = 0, reader = 0; void handshake (pthread_mutex_t *mutex, pthread_cond_t *cond, int *v1, int *v2) { pthread_mutex_lock(mutex); *v1 = 1; while (!*v2) pthread_cond_wait(cond, mutex); pthread_cond_signal(cond); *v2 = 0; pthread_mutex_unlock(mutex); }
And now we insert its call to the beginning of our functions.
void *enter_pass(void *a) { handshake(&mut, &wake_up, &reader, &checker); ... }
And in check_pass () we will rearrange variables
void *check_pass(void *a) { handshake(&mut, &wake_up, &checker, &reader); ... }
Everything. Now the functions will wait for each other and the program can be run, for example,
echo abc rireii password | ./a.out
Until the flow with check_pass is ready, scanf will not be called.
UPDATE
After discussion in the comments, “brushed” the program, now both threads correctly exit, returning to main, incl. at the end of the input (EOF), the reader waits until the checker allows him to enter the next password (or says that it’s enough to read - the password is correct). To do this, add 3 variables (go, pass (continued reader) and check_it (continued checker)).
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> char password[] = "password"; char str[30]; pthread_cond_t wake_up; pthread_mutex_t mut; volatile int checker = 0, reader = 0, go = 1, pass = 0, check_it = 0; void handshake (pthread_mutex_t *mutex, pthread_cond_t *cond, volatile int *v1, volatile int *v2) { pthread_mutex_lock(mutex); *v1 = 1; while (!*v2) pthread_cond_wait(cond, mutex); pthread_cond_signal(cond); *v2 = 0; pthread_mutex_unlock(mutex); } void *enter_pass(void *a) { handshake(&mut, &wake_up, &reader, &checker); puts("reader ok"); while (go) { printf("Enter password:\n"); int rc = scanf("%s", str); pthread_mutex_lock(&mut); if (rc != 1) go = 0; check_it = 1; // send to checker signal "password ready..." pthread_cond_signal(&wake_up); pass = 0; // prepair to wait checker's signal while (!pass) // wait checker send "continue..." (set pass = 1) pthread_cond_wait(&wake_up, &mut); pthread_mutex_unlock(&mut); } puts("reader fin"); } void *check_pass(void *a) { handshake(&mut, &wake_up, &checker, &reader); puts("checker ready"); while (go) { pthread_mutex_lock(&mut); while(!check_it) // wait scanf in reader done (and reader set check_it = 1) pthread_cond_wait(&wake_up, &mut); check_it = 0; // reset variable for next iteration if (go) { if(!strcmp(str , password)) { printf("true\n"); go = 0; } else puts("Wrong password, try another"); } pass = 1; // send to reader signal "continue..." pthread_cond_signal(&wake_up); pthread_mutex_unlock(&mut); } puts("checker fin"); } int main (int ac, char *av[]) { pthread_t thread1, thread2; pthread_mutex_init(&mut, NULL); pthread_cond_init (&wake_up, NULL); pthread_create(&thread1, NULL, enter_pass, 0); pthread_create(&thread2, NULL, check_pass, 0); pthread_join(thread1, NULL); pthread_join(thread2, NULL); return puts("End"), fclose(stdout) == EOF; }
Pay attention to the volatile
attributes of variables shared by different threads (they are also in the handshake () arguments).
By the way, the handshake function is disposable , i.e. threads can safely use it only when external (before they are started) initialization of checker and reader variables.
If something is unclear, ask, I will try to explain.
pthread_join
. - VladD