0

I have a question regarding linux kernel scheduling.

We know that, usually, linux maintains the current largest pid. If we want to start a new process, the kernel will use that largest id. So, if we kill and restart a new process, the process id are not sequential. Linux will use the largest id until it hits a limit.

But my question is how linux decides thread ID. Say, process A and B are running. Process A crashes but process B is spawning new threads. Will process B just reuse that old tid belonging to process A, or, process B will also use the largest id as tid. Which case is more often? Do we have documents?

Thanks.

  • 1
    You have complete source code as the best documentation possible. – Luis Colorado Jan 29 '16 at 08:38
  • Hi Luis. Thanks for the reply. Sorry I can not find the source code. This is not how CPU schedules threads, this is how system decides threadID. Mind if tell me more? Thanks. – user2988877 Feb 02 '16 at 18:59
  • 1
    **www.kernel.org**: there you'll get the complete original source code of linux kernel. The whole kernel repository (including all versions) can be downloaded there as a git repository. – Luis Colorado Feb 03 '16 at 05:42

2 Answers2

0

The kernel sets a maximum number of process/thread ids and simply recycles identifiers when the threads are garbage collected. So if process B spawns enough threads it will eventually reclaim thread ids from process A assuming it has been properly destroyed

Edit: Here are some links that can provide you with more specific answers

Difference between pid and tid https://stackoverflow.com/a/8787888/5768168

"what is the value range of thread and process id?" what is the value range of thread and process id?

"Linux PID recycling" https://stackoverflow.com/a/11323428/5768168

"Process identifer" https://en.wikipedia.org/wiki/Process_identifier#Unix-like

"The Linux kernel: Processes" https://www.win.tue.nl/~aeb/linux/lk/lk-10.html

Community
  • 1
  • 1
bgarcia
  • 154
  • 6
  • Hello. Thanks for the reply. So, the maximum number of thread id maintained by kernel is different from the maxpid, right? Suppose kernel maintains maxpid which is the maximum available pid number for next process. Of course, between 1 and maxpid there are many unused(dead) threads/pids. The "maximum number of thread ids" will blindly use those numbers betwee 1 and maxpid. Am I right? – user2988877 Feb 02 '16 at 19:02
  • So, when kernel starts new process, it will choose pid from maxpid+1. But when kernel spawns thread, it will pick one from within 1 and maxpid? – user2988877 Feb 02 '16 at 19:03
  • I am asking this question because one of my project depends on this tid/pid. We check /proc/id to tell if a thread exist. Each time if a process is a writer we write its tid to somewhere persistent. But process may crash. Next time it comes up, our code will check that persistent field. If that field is not 0 and if /proc/number is there pointing to a valid thread, our code will think there is another writer. So, given this, it looks like our design is not good. There is chance another thread is spawned using same tid. Am I right? – user2988877 Feb 02 '16 at 19:06
  • I updated my answer with some links you should check out. – bgarcia Feb 03 '16 at 03:17
  • If a process exits (i.e. the 'main' thread exits), all of its threads should exit as well. Unless i'm mistaken, this means that if your process crashes, you cannot depend upon those specific thread ids that you have written to a persistent file. – bgarcia Feb 03 '16 at 03:43
  • Thanks Bgarcia. I described my problem in more details to reply Todd's comment. "As new processes fork in, PIDs will increase to a system-dependent limit and then wrap around. The kernel will not reuse a PID before this wrap-around happens. ". But I am asking about how new threads get their tid. It is confusing when we say process is light weight thread, but their ids are generated differently. – user2988877 Feb 03 '16 at 06:00
0

It sounds like you need to run your threads in with a PTHREAD_CREATE_JOINABLE attribute passed to pthread_create(), then have one reaper thread in your process dedicated to using pthread_join() or pthread_tryjoin() to wait for terminated threads. Rather than having an outside process trying to sort it out, have your process record the PID/TID pair after pthread_create() succeeds and have the reaper thread remove the pair when it detects the thread has terminated.

I typically combined that with a main thread that did nothing but spawn the thread-creation and reaper threads, then wait for a termination signal and terminate the thread-creator and reaper. The thread-creator stops immediately when signaled, the reaper stops when no more unterminated threads are running, the main thread terminates when both the thread-creator and reaper threads can be pthread_join()'d. Since the main thread's so simple it's unlikely to crash, which means most crashes in work threads simply deliver them to the reaper. If you want absolute certainty, your outside process should be the one to start your main process, then it can use wait() or it's siblings to monitor whether the main process has terminated (normally or by crashing).

Todd Knarr
  • 1,255
  • 1
  • 8
  • 14
  • Thanks Todd. I think I did not describe my problem clearly. My problem is like this: we maintain the tid outside in persistent storage, to indicate that an in-memory database has a writer. Our in-memory database(cache) is single writer (multiple reader). That tid is for access control. Say, if A is old writer, but it crashes, that tid is still maintained in persistent storage. Then, A comes back again and wants to continue his writer permission. However, it looks like process B is possible to gain that tid by spawning threads. Then, process A will be rejected. – user2988877 Feb 03 '16 at 05:52
  • This design is OK if processes are all single thread. The linux will schedule tid/pid from the max limit. If A crashes, no one will use his tid. Even there are new processes started, they will use pid much larger than A's old pid, because they get their pid from the max limit. So, no one will use A's old pid for a while. However, if processes can spawn threads dynamically, it seems this design can be broken. Thanks. – user2988877 Feb 03 '16 at 05:55
  • Yes, PIDs are assigned in rotation so the PID of a crashed process won't be reused until the system's cycled through the entire range of PIDs and come back to that one again. Your design looks incredibly fragile, though, and not just the aspect you describe. You can't control PIDs nor kernel thread IDs, so you can't guarantee process A would get the same TID even if it hadn't been grabbed by another process. You can't guarantee the kernel behavior won't change in the future either. – Todd Knarr Feb 03 '16 at 22:22
  • One convenient way of doing this between processes is to create a lockfile for each database, then use the `flock()` call to lock that file to indicate a writer has access to the database. The lock will automatically be released if the process crashes, as part of closing the file descriptor. If you need the lock to persist, consider using a lock manager process and IPC to request and release locks. – Todd Knarr Feb 03 '16 at 22:33
  • Thanks for the reply. Yes, the design is fragile. :) Thanks for the suggestion. – user2988877 Feb 05 '16 at 19:26