pthread_setaffinity_np(3)

๐Ÿ’– pthread_setaffinity_np(3) ๐Ÿ’–

okay bestie, listen. this is a page from the Library Functions Manual, and it's about the two functions that let you tell a thread exactly which CPUs it's allowed to vibe on. it's giving "CPU matchmaking, but make it syscalls" fr fr. โœจ

๐ŸŒธ NAME ๐ŸŒธ

pthread_setaffinity_np, pthread_getaffinity_np โ€” set/get CPU affinity of a thread

๐Ÿ“š LIBRARY ๐Ÿ“š

POSIX threads library (libpthread, -lpthread)

โœจ SYNOPSIS โœจ

#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <pthread.h>

int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize,
                           const cpu_set_t *cpuset);
int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize,
                           cpu_set_t *cpuset);

๐Ÿฆ‹ DESCRIPTION ๐Ÿฆ‹

so pthread_setaffinity_np() takes the CPU affinity mask of the thread called thread and sets it to the CPU set that cpuset is pointing at. and if the call goes through successfully, and the thread isn't already chilling on one of the CPUs in cpuset, then boom โ€” it gets migrated to one of those CPUs. no cap. ๐Ÿ’…

then pthread_getaffinity_np() is the lil reverse one: it hands you back the CPU affinity mask of thread, dropping it into the buffer that cpuset points to.

want the full tea on CPU affinity masks? that's over in sched_setaffinity(2). and if you wanna know about the whole set of macros for poking at and inspecting CPU sets, go read CPU_SET(3). ๐ŸŽ€

the cpusetsize argument is the length (in bytes) of the buffer that cpuset points to. normally you'd just pass sizeof(cpu_set_t) and call it a day. (though it can totally be some other value if you're out here using the macros described in CPU_SET(3) to dynamically allocate a CPU set. icon behavior.)

๐Ÿ‘‘ RETURN VALUE ๐Ÿ‘‘

on success these functions return 0. on error they return a nonzero error number. that's it, that's the whole vibe check.

๐Ÿ’€ ERRORS ๐Ÿ’€

  • EFAULT โ€” a supplied memory address was invalid. ๐Ÿ˜ญ
  • EINVAL (from pthread_setaffinity_np()) โ€” the affinity bit mask mask contains no processors that are currently physically on the system and permitted to the thread according to any restrictions that may be imposed by the "cpuset" mechanism described in cpuset(7).
  • EINVAL (from pthread_setaffinity_np()) โ€” cpuset specified a CPU that was outside the set supported by the kernel. (fun fact: the kernel configuration option CONFIG_NR_CPUS defines the range of the set supported by the kernel data type used to represent CPU sets.)
  • EINVAL (from pthread_getaffinity_np()) โ€” cpusetsize is smaller than the size of the affinity mask used by the kernel.
  • ESRCH โ€” no thread with the ID thread could be found. she's not here bestie ๐Ÿซถ

๐ŸŒˆ ATTRIBUTES ๐ŸŒˆ

if you wanna know what these terms even mean, attributes(7) has you covered. but here's the breakdown:

  • Interface: pthread_setaffinity_np(), pthread_getaffinity_np()
    • Attribute: Thread safety
    • Value: MT-Safe โœจ slay

โญ STANDARDS โญ

GNU. which is literally why these names have that "_np" suffix โ€” it stands for nonportable. iykyk. ๐Ÿ™ˆ

๐Ÿงš HISTORY ๐Ÿงš

glibc 2.3.4.

and okay, tiny lore drop: in glibc 2.3.3 only, there were versions of these functions that did not have a cpusetsize argument. instead, the CPU set size handed to the underlying system calls was always sizeof(cpu_set_t). different era, different chaos. ๐Ÿ’œ

๐ŸŒธ NOTES ๐ŸŒธ

after you call pthread_setaffinity_np(), the set of CPUs the thread will actually run on is the intersection of the set you specified in the cpuset argument and the set of CPUs actually present on the system. and the system may restrict things even further if the "cpuset" mechanism described in cpuset(7) is in play. these restrictions on the actual set of CPUs the thread runs on are silently imposed by the kernel โ€” so no, you don't get a heads up. ๐Ÿ’€

these functions are implemented on top of the sched_setaffinity(2) and sched_getaffinity(2) system calls.

also: a new thread created by pthread_create(3) inherits a copy of its creator's CPU affinity mask. family traits, literally. ๐Ÿ‘‘

๐ŸŽ€ EXAMPLES ๐ŸŽ€

in this program, the main thread uses pthread_setaffinity_np() to set its CPU affinity mask to include CPUs 0 to 7 (which, lowkey, may not all be available on the system), and then calls pthread_getaffinity_np() to check what the resulting CPU affinity mask of the thread actually ended up being.

#define _GNU_SOURCE
#include <err.h>
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>

int
main(void)
{
    int s;
    cpu_set_t cpuset;
    pthread_t thread;

    thread = pthread_self();

    /* Set affinity mask to include CPUs 0 to 7.  */

    CPU_ZERO(&cpuset);
    for (size_t j = 0; j < 8; j++)
        CPU_SET(j, &cpuset);

    s = pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset);
    if (s != 0)
        errc(EXIT_FAILURE, s, "pthread_setaffinity_np");

    /* Check the actual affinity mask assigned to the thread.  */

    s = pthread_getaffinity_np(thread, sizeof(cpuset), &cpuset);
    if (s != 0)
        errc(EXIT_FAILURE, s, "pthread_getaffinity_np");

    printf("Set returned by pthread_getaffinity_np() contained:\n");
    for (size_t j = 0; j < CPU_SETSIZE; j++)
        if (CPU_ISSET(j, &cpuset))
            printf("    CPU %zu\n", j);

    exit(EXIT_SUCCESS);
}

๐Ÿ”ฅ SEE ALSO ๐Ÿ”ฅ

sched_setaffinity(2), CPU_SET(3), pthread_attr_setaffinity_np(3), pthread_self(3), sched_getcpu(3), cpuset(7), pthreads(7), sched(7)


and that's the whole page, bestie!! this came from Linux man-pages 6.20, dated 2025-09-21. go pin some threads to some CPUs and be the main character of your own scheduler. ๐Ÿ’–โœจ๐Ÿฆ‹ no cap, you got this. ๐Ÿซถ

๐Ÿ“ฆ where this page comes from
  • arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • ๐Ÿ“œ the page's license: Linux-man-pages-copyleft
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms