Developing operating systems IS my day job. The multi-threaded scenario described in the question is similar to ones that I have dealt with many times.
To implement a proper first-come-first-serve queue as described in the question, the following constructs are needed: a list that tracks which students are waiting, a mutex to control access to this list, a semaphore upon which the TA waits, and a semaphore for EACH student. I also recommend one more semaphore for the TA to use with the selected student to indicate when the help session is done.
The student must lock the mutex and check if the chairs are full. If full, the student must unlock the mutex and return to coding. If a chair is available, the student takes one and signals the TA's semaphore that he is waiting. Next (and this is critical) the student waits on his own semaphore.
The TA meanwhile does the following: wait on the TA's semaphore, and once woken up, locks the mutex and checks the chairs. It then gets the identity of the next person in the chair and signals their semaphore. This in turn wakes up the appropriate student.
I have coded up a solution for this (it just needs a few small tweaks in the comments) and it is ready for you if you want this correct solution. I hope to hear from you.
Peter Mitsis