Re: Threads and processes on Linux

From: doug (noone_at_nowhere.co.uk)
Date: 04/01/05


Date: Thu, 31 Mar 2005 23:10:45 GMT


<loic-dev@gmx.net> wrote in message
news:1112273796.254309.214020@z14g2000cwz.googlegroups.com...
> Hello Gus,
>
>> I have often heard that in a Linux environment there is no difference
>> between threads and processes. I want to know if that is merely
>> "rhetoric" or if that is really so.
>
> It is more than "rhetoric". From a scheduler perspective, threads and
> processes are the same entity.
>
> Actually, Linux views a thread as a process with some special
> properties: it shares with its 'parent task' (the spawning thread) the
> things that are needed to make it to *behave like* a thread. Namely,
>
> (o) memory descriptors and all Page tables. This means that the child
> task runs in the same memory space as the parent task. All memory
> mappings or write operations are visible in both entities.
>
> (o) file system information (root directory, current directory and
> umask).
>
> (o) open files
>
> (o) signal handlers.
>
> The fact that threads were modelled as processes is visible when using
> LinuxThreads and/or older 2.4.x kernel. For instance, each spawned
> thread has a different pid, and are children of the so-called manager
> thread.
>
> With the advent of NPTL and 2.6.x kernel, a process *appears* as a
> collection of thread, where threads are peers. But it is an
> _abstraction_ provided by NPTL: for instance, a sibling relationship
> between threads still exists, but is now hidden to you. Inside the
> kernel, threads and processes are similar entities (the scheduler won't
> even bother to make any distinction).
>
>
>> For example, I have seen that getpid() in all threads returns the
> same value
>> (as I think it should).
>
> Only with NPTL.
>
>
>> This means from the perspective of operations associated with
> processes
>> (ps, signal etc.), all the threads are viewed as a single entity.
>
> Yes, because NPTL provides an abstraction that let you think it is so.
> But, in reality, the threads of a process are different entities.
>
>
>> Also, if the spawning thread terminates (e.g. it does not do a join
> on
>> the spawned thread), the spwaned thread also seems to terminate. In
>> other words, the lifetime of a spawned thread does not seem to exceed
>> the lifetime of the spawning thread.
>
> Generally speaking, this is not correct. You can perfectly create a
> thread that lasts more than the spawner thread. Consider for instance
> the following simple program:
>
> #include <stdio.h>
> #include <pthread.h>
> #include <unistd.h>
>
> void*
> my_thread(void* ignore)
> {
> int i;
>
> for (i=5; i>=1; i--) {
> printf ("%d...", i); fflush(stdout);
> sleep(1);
> }
> printf ("0\nCiao!\n");
> return NULL;
> }
>
> int
> main()
> {
> pthread_t tid;
>
> pthread_create (&tid, NULL, my_thread, NULL);
> printf ("Main terminate\n");
> pthread_exit (NULL);
> printf ("Never reached!\n");
> return 0;
> }
>
> If you comment the pthread_exit(NULL) out in the main(), then you get
> the behavior that you have described. However, it is not a general
> rule, but a particular behavior of the main() thread: when main()
> returns, all threads in the process go away. That's because of how the
> C language defines main(), more than anything else. It's simplest to
> imagine that the environment calls main like this:
>
> exit(main(argc, argv, envp));
>
> So that when main() returns, that return value is passed to exit(),
> which tears down the process, and all threads therein.
>
>
>> So what exactly are we saying when we state that "there is no
>> difference between threads and processes on Linux"?
>
> I Hope, things got clearer now.
>
>
> Cheers,
> Loic.
>

Loic,

Thanks for the post - very helpful - it clears a few things up for me!

I'm going to be cheeky and ask you a question that I posted below about a
multithreaded bit of code I'm writing. Just incase you didn't see it :)
I've got a 2.4 kernel with linuxthreads, and an app with about 300 threads
doing network I/O in 20 millisecond bursts. On a single CPU box, this is
fine. On an SMP box, performance drops through the floor. There are no
data pages shared between threads. vmstat, etc. show the processors 60%
idle.

My theory is that each thread is being repeatedly scheduled on a different
CPU, and so a lot of time is being spent loading the memory accessed by the
thread into the CPU cache, and then (once it's dirtied) invalidating the
cache entries on the last processor to host it. Am I in the right ballpark?
Even playing the right sport?

I hacked a box so it would run the thread affinity stuff added to the 2.5.8
kernel, but i'm not sure of my success. Binding each thread to a particular
CPU made no difference. Binding them all to a single CPU (id 0) made a
*huge* difference, but it still wasn't as good as uniprocessor.

I only got thread affinity - I didn't get interrupt affinity. My next
theory is interrupts. The 2.4 kernel round-robins responsibility for
handling interrupts around the cpus - each receives them for a short period.
Each I/O operation generates an interrupt. If it's not delivered to the
correct processor (75% chance), time is wasted transmitting the information
between the cpu receiving the interrupt and the cpu running the thread.
 Ok - what sport am I playing now?

Phew. That's a lot of gumph. Upshot:
- are my theories anywhere correct? And if not, what could be causing the
performance drop on SMP? (I realise this is impossible to answer! But
there's no data sharing, all objects and per-thread memory accesses lie on
per-thread memory pages, there's no swapping going on, all data is resident
in main memory, processors are barely sweating, aaarrggh!)
- are there any reliable interrupt/thread affinity patches for 2.4 (being
lazy here - I will try to find out myself)
- is this function available in 2.6 and/or NTPL? (ditto)

Thanks for all the useful info in the post.

Doug



Relevant Pages

  • [PATCH] Update Documentation/DocBook/kernel-hacking.tmpl
    ... Kernel Hacking. ... not associated with any process, serving a softirq, tasklet or bh; ... For example, while a softirq is running on a CPU, no other ... but a hardware interrupt can. ...
    (Linux-Kernel)
  • Re: [parisc-linux] [patch 15/23] Add cmpxchg_local to parisc
    ... could be vastely used in the kernel. ... the local ops has just been standardized in 2.6.22 though a patchset I ... I always thought preemption required some sort of interrupt or trap. ... that only one CPU writes to the local_t data. ...
    (Linux-Kernel)
  • Re: Help with a driver im writing.
    ... Tasklets don't interfere each other on single CPU with non-preemeptable ... put it into a critical section with interrupt off anyway. ... > It's running on kernel version 2.6.14 single intel cpu, ... > My write routine is a loop in which i shift data out to the ...
    (comp.os.linux.development.system)
  • Oops in 2.6.28-rc9 and -rc8 -- mtrr issues / e1000e
    ... Bios 1.04beta did show correct memory sizing in dmidecode, ... I hope this is as simple as me doing something glaringly wrong in the kernel ... DMI present. ... CPU: L2 cache: 6144K ...
    (Linux-Kernel)
  • Re: 2.6.28-rc9 panics with crashkernel=256M while booting
    ... Allocated 00d00000 bytes for kernel @ 02d00000 ... Device tree strings 0x0000000003a90000 -> 0x0000000003a917bc ... CPU maps initialized for 2 threads per core ... Node 0 Memory: ...
    (Linux-Kernel)