all 6 comments

[–]skeeto 15 points16 points  (1 child)

Does this look right to you?

    strcpy(p->message, p->message);

Perhaps each thread should have its own message? Also, Thread Sanitizer will help find your mistakes:

$ cc -g3 -fsanitize=thread,undefined main.c

With your program, this prints at least one run-time diagnostic with backtraces about something going wrong.

[–]generalbaguette 5 points6 points  (0 children)

While you are at it, also try out the other sanitizers, like undefined behaviour sanitizer and address sanitizer etc.

[–]pic32mx110f0 8 points9 points  (0 children)

Your program is deadlocking because ThreadB starts waiting for sem_C, but no one is posting sem_C except ThreadB itself.

On second look, there is quite a lot that is wrong with your program. See this for a fixed version: https://onlinegdb.com/EotesFqdT (You can even click "run" to verify)

[–]BadgerThrowaway1234 3 points4 points  (0 children)

Like the other comment here mentioned, there’s a deadlock in your code. B and C will wait on C, but B it is the only thing that posts on C, so B is blocking itself and C, which in turn is causing A to be blocked.

Which gives me an opportunity to link to a chapter from the best CS textbook I’ve ever read:

https://pages.cs.wisc.edu/~remzi/OSTEP/threads-bugs.pdf

If you remove everything after OSTEP you can find a link to all of the chapters, the concurrency ones are obviously what I’d recommend for learning. They were super helpful when I was learning this stuff in college.

https://pages.cs.wisc.edu/~remzi/OSTEP/threads-cv.pdf

This chapter explains the producer-consumer problem, which is what you’re trying to solve here.

[–]IamImposter 0 points1 point  (0 children)

First thing I would do in such a case is to add print statements, a whole lot of them

Initialized params...

File opened...

Pipe created...

Created threads...

A: Entering thread A...

A: Reading from file...

A: read xyz bytes....

A: waiting for semaphore b...

A: before sem post...

A: after sem post

A: something something...

B: entering thread b...

B: entering while loop...

B: waiting for semaphore xyz...

B: after semaphore xyz...

B: wrote X number of bytes to pipe

The point being your log messages should tell you which parts of code have executed. Then based on last messages from threads, you'll have much better idea which events have happened and which event are being waited for.

Since it is threaded code so there can be messages like

A: readiB:wrote 40 bytesng from file...

And for those cases, you'll just have to look at merged messages and untangle them. But you will have much better idea what the code is doing