Thread synchronization with mutex
Since pthread_create() returns an error number on failure, you can put ret into strerror() to get the associated error message instead of just printing the number:

fprintf(stderr, "Thread 1 creation failed: %s\n", strerror(ret));


Notice that I'm calling fprintf() instead of printf().  Since you're printing an error, it must be sent to stderr, not stdin (used by default with printf()).

Also, while you'd normally not need all this code for printing an error, it's necessary since pthread_create() doesn't set errno (which is why ret is useful here).

For code that does set errno (which would be stated on man pages), you'd only need to call perror() to print the corresponding error message:

perror("&lt;insert source of failure here&gt;");


This would also eliminate the need for variables like ret in such code.  However, with pthread_create() and related functions, you could probably just put errno in its place and then use perror().
The functions called by pthread_create() should still return something.  Since the return value won't be useful here, you can just return NULL.
There's no need to call exit() right at the end of main().  You're preventing it from returning a value, and it'll always return 0 at this point anyway.
This isn't a criticism, but a tip: make sure you're running this through valgrind to check for any memory leaks along the way.

Actually, this may already cause a leak, but I haven't checked to make sure.  If it does, then you may need to call both pthread_mutex_destroy() and pthread_cond_destroy() before exiting the program at any point.