linux进程与线程的核绑定操作

linux进程与线程的核绑定

1. 进程核绑定

进程自己调用 sched_setaffinity 来做核绑定。

linux系统上,直接 man sched_setaffinity,可以获取详细的说明
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sched.h>

   int sched_setaffinity(pid_t pid, size_t cpusetsize,
                         const cpu_set_t *mask);

   int sched_getaffinity(pid_t pid, size_t cpusetsize,
                         cpu_set_t *mask);

配置CPU核参数的API,进程和线程都使用此API,linux上man CPU_ZERO 可以看相关的所有API
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sched.h>

   void CPU_ZERO(cpu_set_t *set);

列几个常用的:

void CPU_ZERO(cpu_set_t *set); /* 初始化或者清除CPU参数 */
void CPU_SET(int cpu, cpu_set_t *set); /* 增加指定core绑定 */
void CPU_CLR(int cpu, cpu_set_t *set); /* 删除指定core绑定 */
int CPU_ISSET(int cpu, cpu_set_t *set); /* 确定指定的core是否在绑定参数中 */
int CPU_COUNT(cpu_set_t *set); /* 查询CPU配置中,有多少个core配置信息 */

读完后,自己写个测试的demo

int main(int argc, char *argv[])
{
    int core_id;
    int core_total_num;
    cpu_set_t mask;

    /* 获取系统中总核数 */
    core_total_num = sysconf(_SC_NPROCESSORS_CONF);

    /* 测试使用app参数,作为绑定核编号,单进程绑定多个核的代码,可以自己构造参数 */
    core_id = atoi(argv[1]);
    if (core_id >= core_total_num) {
        printf("Usage: %s core_id should less then %d", argv[0], (core_total_num - 1));
        exit(EXIT_FAILURE);
    }

    CPU_ZERO(&mask);
    CPU_SET(core_id, &mask);
    /* 入参pid = 0,表示运行这段代码的进程,或者使用getpid()获取自身的进程 */
    if (sched_setaffinity(getpid(), sizeof(mask), &mask) < 0) {
        perror("sched_setaffinity fail:");
    }
    for (;;) {
        usleep(10);
    }
}

2. 线程核绑定

进程启动多个线程,传递需要绑定的cpu参数,线程内部自行配置核绑定。
绑定成功后,再配置线程名字,便于后面ps等查询和操作

linux上使用 man
#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);
   int pthread_setname_np(pthread_t thread, const char *name);
   int pthread_getname_np(pthread_t thread, char *name, size_t len);
void test_thread(void *cpu_core)
{
    int ret;
    /* pthread_setaffinity_np 的入参名字长度限制为16 */
    char thread_name[16] = {0};
    int core_id = *(int*)cpu_core;
    cpu_set_t cpu_mask;
    pthread_t thread_id = pthread_self();

    CPU_ZERO(&cpu_mask);
    CPU_SET(core_id, &cpu_mask);

    /* 配置线程核绑定 */
    ret = pthread_setaffinity_np(thread_id, sizeof(cpu_set_t), &cpu_mask);
    if (ret != 0) {
        printf("pthread_setaffinity_np fail. thread_id = %lu, core_id = %d \r\n", thread_id, core_id);
    }

    /* 获取核绑定状态,确定绑定成功 */
    ret = pthread_getaffinity_np(thread_id, sizeof(cpu_set_t), &cpu_mask);
    if (ret != 0) {
        printf("pthread_getaffinity_np fail. thread_id = %lu \r\n", thread_id);
    }

    if (CPU_ISSET(core_id, &cpu_mask)) {
        /* 确定绑定成功后,设置线程名 */
        (void)sprintf(thread_name, THREAD_NANE_LEN, "test@core%d", core_id);
        ret = pthread_setname_np(thread_id, thread_name);
        if (ret != 0) {
            printf("pthread_setname_np fail. thread_id = %lu ret = %d\r\n", thread_id, ret);
        }
    } else {
        printf("thread[%lu] band on cpu[%d] fail.\n", thread_id, core_id);
    }

    /* 打印线程名与tid pid */
    ret = pthread_getname_np(thread_id, thread_name, THREAD_NANE_LEN);
    if (ret != 0) {
        printf("[%s] pthread_getname_np fail. ret = %d\r\n", __func__, ret);
    } else {
        printf("%s, tid=%d, pid=%d.\r\n", thread_name, gettid(), getpid());
    }

    for (;;) {
        usleep(10);
    }
}

int main(int argc, char *argv[])
{
    int core_num;
    int core_id = 0;
    int core_max = sysconf(_SC_NPROCESSORS_CONF);
    pthread_attr_t attr;
    pthread_t thread_id;
    int ret;
    int thread_info[16] = {0};

    core_num = atoi(argv[1]);
    if (core_num > core_max) {
        printf("core_num[%d] should less than core_max[%d].\r\n", core_num, core_max);
        return -1;
    }

    /* 每个core上绑定一个测试线程 */
    for (core_id = 0; core_id < core_num; core_id++) {
        ret = pthread_attr_init(&attr);
        if (ret != 0) {
            printf("pthread_attr_init fail. ret = %d", ret);
        }

        /* 线程参数可以配置,这里不展开了,按需man 找使用方法
        pthread_attr_setstacksize(&attr, PTHREAD_STACK_SIZE);
        pthread_attr_setschedpolicy(&attr, PTHREAD_POLICY);
        pthread_attr_getschedparam(&attr, &sched);
        sched.sched_priority = PTHREAD_PRIORITY;
        pthread_ret = pthread_attr_setschedparam(&attr, &sched);

        主要讲下配置线程分离,可以直接配置参数,或者用pthread_detach,自行选择
        int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
        int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
        PTHREAD_CREATE_DETACHED
               Threads that are created using attr will be created in a detached state.
        PTHREAD_CREATE_JOINABLE
               Threads that are created using attr will be created in a joinable state.

        配置线程属性参数的方式,理论上可能有如下的缺陷,一般都用 pthread_detach:
        线程创建函数还未来得及返回时子线程提前结束导致返回的线程号是错误的线程号的情况。
        因为采用这种方法,即使子线程提前结束(先于pthread_create返回),但是子线程还未处于分离状态,
        因此其PCB的残留信息依然存在,如线程号等一些系统资源,
        所以线程号等系统资源仍被占据,还未分配出去,所以创建函数返回的线程号依然是该线程的线程号
        */

        /* 注意不要直接传core_id给线程,因为线程是访问的core_id地址,
        线程还没启动,就已经走到for的下个循环了,core_id已经变化了,
        注意此局部变量要保证在线程创建完成前,不能消亡(比如放到了个子函数中,子函数已经结束了,线程还未创建完成) */
        thread_info[core_id] = core_id;

        ret = pthread_create(&thread_id, &attr, (void*)test_thread, &(thread_info[core_id]));
        if (ret != 0) {
            printf("pthread_create fail. ret = %d", ret);
        }

        ret = pthread_detach(thread_id);
        if (ret != 0) {
            printf("pthread_detach fail. thread_id = %lu, ret = %d", thread_id, ret);
        }
        printf("set test_thread at cpu[%d].\r\n", core_id);
    }

    for (; ; ) {
        usleep(1);
    }
}

3. shell下命令行taskset配置进程核线程核绑定

taskset --help
Usage: taskset [options] [mask | cpu-list] [pid|cmd [args…]]

Show or change the CPU affinity of a process.

Options:
-a, --all-tasks operate on all the tasks (threads) for a given pid
-p, --pid operate on existing given pid
-c, --cpu-list display and specify cpus in list format
-h, --help display this help
-V, --version display version

The default behavior is to run a new command:
taskset 03 sshd -b 1024 /* 执行的sshd -b 1024的APP,绑定到core0和1上(mask 03) /
You can retrieve the mask of an existing task:
taskset -p 700 /
查看进程编号700的绑定状态,返回值是mask形式 /
/
返回打印例子 /
pid 1070’s current affinity mask: 3 /
绑定在0和1 core上 /
Or set it:
taskset -p 03 700 /
绑定线程700到core0和1上(mask 03) /
List format uses a comma-separated list instead of a mask:
taskset -pc 0,3,7-11 700 /
绑定线程700到core0和3以及7-11上 */
Ranges in list format can take a stride argument:
e.g. 0-31:2 is equivalent to mask 0x55555555

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值