The Mechanism of Inheritance
In Linux cgroup v1, the fundamental unit of resource management is the process (specifically, the task structure). When a new thread is created viaclone() or fork(), the kernel checks the cgroup settings of the creating thread. If the parent is in a specific directory under /sys/fs/cgroup/<type>/, the child thread is immediately placed in that same directory. This behavior is hardcoded into the kernel’s task creation logic.
There is no separate "thread" cgroup controller in v1. Controllers like cpu, memory, and blkio operate on processes. Because threads within a single process share the same address space and file descriptors, separating them into different cgroups would break the logical consistency of the application. Therefore, the kernel treats the entire set of threads belonging to one process as a single entity for cgroup purposes.
Why Individual Thread Movement Fails
Attempting to move a specific thread ID (TID) to a different cgroup using thetasks file will fail with an error such as EPERM or EINVAL. This is because the tasks file expects a full process ID (PID), which corresponds to the unique identifier of the process group leader. While a TID is technically a PID in Linux, moving a non-leader thread independently violates the atomic nature of process migration.
The kernel enforces this rule to prevent resource accounting anomalies. If you could isolate a single thread, it might consume memory or CPU cycles that should be accounted for by the main process, leading to inaccurate limits. Consequently, all threads must reside in the same cgroup as their parent. To change the cgroup of any thread, you must move the entire process, including all its associated threads.
Correcting Misconceptions About /sys/fs/cgroup
It is important to clarify that/sys/fs/cgroup is not read-only by default. It is a virtual filesystem mounted by the system administrator or init system to expose cgroup controllers. Users with appropriate permissions can write to files within this hierarchy, such as cgroup.procs or tasks, to manage resource allocation. However, even with write permissions, the constraint regarding individual thread movement remains strict due to kernel design, not filesystem permissions.
Misunderstanding this often leads developers to believe that fine-grained thread-level isolation is possible in v1. It is not. If granular control over individual execution contexts is required, administrators must look toward cgroup v2, which introduces more flexible task management features, or use namespaces and capabilities for security isolation rather than resource constraints.
Best Practices for Process Management
When managing resources in cgroup v1, always operate at the process level. Use tools likesystemd-run or direct writes to cgroup.procs to attach entire services or applications. For example, if you have a multi-threaded web server, attaching the master process to a cgroup with a CPU quota will effectively limit the combined CPU usage of all worker threads.
This approach simplifies administration. You do not need to track every thread spawned by your application. The kernel handles the inheritance transparently. As long as the parent process remains in the correct cgroup, all subsequent threads will automatically comply with the defined policies. This reduces configuration complexity and minimizes the risk of misconfiguration errors that could lead to resource exhaustion or security vulnerabilities.
For related information on service management and system configuration, you may find these articles useful:
Preserve Order of Closing Services While Shutting Down Linux
Primary User Group for Linux Desktop Applications
Frequently Asked Questions
Can I move a specific thread to a different cgroup in v1?
No, you cannot move individual threads independently in cgroup v1. The kernel requires atomic movement of the entire process, meaning all threads associated with that process must stay together in the same cgroup.
What happens to threads when I move the parent process?
All threads belonging to the parent process are moved along with it. The kernel treats the process as a single unit for cgroup operations, ensuring that resource limits apply consistently to the entire set of execution contexts.
Is /sys/fs/cgroup always read-only?
No, /sys/fs/cgroup is typically writable by root or users with specific permissions. It is a virtual filesystem used to interact with cgroup controllers, but access depends on your system’s security policies and mount options.
How does cgroup v2 differ in this regard?
Cgroup v2 still operates primarily on processes but offers more flexible task management and unified hierarchy. While it improves upon v1, individual thread isolation is still generally not supported in the same way namespaces provide isolation.
Why doesn't the kernel support per-thread cgroup assignment?
Threads share memory and resources, making per-thread accounting complex and potentially inconsistent. Enforcing process-level cgroup membership ensures accurate resource tracking and prevents conflicts in memory and CPU usage limits.