c語言設置cpu affinity (設置程序需要使用的cpu內核) cpu mask

最近打算寫個小程序, 需要控制使用的是哪個 cpu 內核,所以做了一些調查, 整理一下分享給大家。 

主要參考: 

http://www.gnu.org/software/libc/manual/html_node/CPU-Affinity.html/

http://stackoverflow.com/questions/7296963/gnu-source-and-use-gnu

https://gcc.gnu.org/ml/fortran/2005-10/msg00365.html

設置想要使用的cpu內核, 因爲現在絕大部分都是多內核的cpu, 其實就是設置cpu的affinity,

網上找的例子這樣寫:


#include <stdio.h>
#include <math.h>
 
#include <unistd.h>
#include <sys/times.h>
#define __USE_GNU
#include <sched.h>

但是, 可以很確定的說,這種寫法是不對的, 因爲在https://gcc.gnu.org/ml/fortran/2005-10/msg00365.html 這裏,很多年以前就說了不能由用戶直接定義 __USE_GNU的宏定義, 雖然這樣做可以正常使用, 能夠編譯通過, 但是違反了一些原則,在工程裏面就不能這麼使用了。


先看一下我總結的代碼:


#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <unistd.h>
#include <sys/times.h>
 
void set_cpu(int id);
 
int main(void)
{
    puts("cpu affinity set");
    set_cpu(0x0003);
 
    while(1)
    {
        //sleep(10);
        //printf("in the while\n");
    }
 
    return 1;
}
 
// setup the cpu set of this program to run on
void set_cpu(int id)
{
    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(id, &mask);
    if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
    {
        fprintf(stderr, "warning: could not set CPU affinity/n");
    }
}

#define _GNU_SOURCE

這個宏定義一定要放在代碼文件的最開始位置, 即使你把它放在了<sched.h>之前,但是如果不是文件最開始部分,那麼也編譯不了。

看一下系統的運行:

可以看到在指定的cpu上運行的程序。

然後, 看一下具體的一些細節。

cpu_set_t 是一個cpu集合, 用於表明使用哪些內核, 所以也可以稱爲是mask, cpu_set_t的實現如下:

typedef struct
{
  __cpu_mask __bits[__CPU_SETSIZE / __NCPUBITS];
} cpu_set_t;

是一個結構體,  __cpu_mask的定義爲:
/* Type for array elements in 'cpu_set_t'.  */
typedef unsigned long int __cpu_mask;

__cpu_mask是一個unsigned long int類型。


運行的時候, 沒有運行CPU_ZERO() 之前 __bits = {0, 140737351860832, 10, 140737354104832, 17, 140737348450122, 16, 17, 10, 4196320, 140737488347648, 140737348456117, 140737351860832, 140737348456959, 140737351860832, 16}

然後運行CPU_ZERO() 將cpu_set都重置爲0, 這個時候:

__bits = {0 <repeats 16 times>}

sched_setaffinity(0, sizeof(mask), &mask) == -1 這句代碼則根據已經設置的cpu mask設置當前進程採用哪個cpu內核運行。

sched_setaffinity()的原型函數爲:

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


This function installs the cpusetsize bytes long affinity mask pointed to by cpuset for the process or thread with the ID pid. If successful the function returns zero and the scheduler will in future take the affinity information into account.

If the function fails it will return -1 and errno is set to the error code:

ESRCH
No process or thread with the given ID found. 
EFAULT
The pointer cpuset is does not point to a valid object. 
EINVAL
The bitset is not valid. This might mean that the affinity set might not leave a processor for the process or thread to run on.
This function is a GNU extension and is declared in sched.h.


來看一下  sched.h 頭文件, 頭文件中有這樣一段:

#ifdef __USE_GNU
/* Access macros for `cpu_set'.  */
# define CPU_SETSIZE __CPU_SETSIZE
# define CPU_SET(cpu, cpusetp)     __CPU_SET_S (cpu, sizeof (cpu_set_t), cpusetp)
# define CPU_CLR(cpu, cpusetp)     __CPU_CLR_S (cpu, sizeof (cpu_set_t), cpusetp)
# define CPU_ISSET(cpu, cpusetp) __CPU_ISSET_S (cpu, sizeof (cpu_set_t), \
                        cpusetp)
# define CPU_ZERO(cpusetp)     __CPU_ZERO_S (sizeof (cpu_set_t), cpusetp)
# define CPU_COUNT(cpusetp)     __CPU_COUNT_S (sizeof (cpu_set_t), cpusetp)
 
# define CPU_SET_S(cpu, setsize, cpusetp)   __CPU_SET_S (cpu, setsize, cpusetp)
# define CPU_CLR_S(cpu, setsize, cpusetp)   __CPU_CLR_S (cpu, setsize, cpusetp)
# define CPU_ISSET_S(cpu, setsize, cpusetp) __CPU_ISSET_S (cpu, setsize, \
                               cpusetp)
# define CPU_ZERO_S(setsize, cpusetp)        __CPU_ZERO_S (setsize, cpusetp)
# define CPU_COUNT_S(setsize, cpusetp)        __CPU_COUNT_S (setsize, cpusetp)
 
# define CPU_EQUAL(cpusetp1, cpusetp2) \
  __CPU_EQUAL_S (sizeof (cpu_set_t), cpusetp1, cpusetp2)
# define CPU_EQUAL_S(setsize, cpusetp1, cpusetp2) \
  __CPU_EQUAL_S (setsize, cpusetp1, cpusetp2)
 
# define CPU_AND(destset, srcset1, srcset2) \
  __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, &)
# define CPU_OR(destset, srcset1, srcset2) \
  __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, |)
# define CPU_XOR(destset, srcset1, srcset2) \
  __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, ^)
# define CPU_AND_S(setsize, destset, srcset1, srcset2) \
  __CPU_OP_S (setsize, destset, srcset1, srcset2, &)
# define CPU_OR_S(setsize, destset, srcset1, srcset2) \
  __CPU_OP_S (setsize, destset, srcset1, srcset2, |)
# define CPU_XOR_S(setsize, destset, srcset1, srcset2) \
  __CPU_OP_S (setsize, destset, srcset1, srcset2, ^)
 
# define CPU_ALLOC_SIZE(count) __CPU_ALLOC_SIZE (count)
# define CPU_ALLOC(count) __CPU_ALLOC (count)
# define CPU_FREE(cpuset) __CPU_FREE (cpuset)
 
 
/* Set the CPU affinity for a task */
extern int sched_setaffinity (__pid_t __pid, size_t __cpusetsize,
                  __const cpu_set_t *__cpuset) __THROW;
 
/* Get the CPU affinity for a task */
extern int sched_getaffinity (__pid_t __pid, size_t __cpusetsize,
                  cpu_set_t *__cpuset) __THROW;
#endif

如果定義了 __USE_GNU 的話, 則定義以下若干宏定義,  但是我們說了, 用戶不能定義 __USE_GNU這個宏, 那麼這是在哪裏的呢?  sched.h最開始包含了 features.h 這個頭文件, 在這個頭文件中有如下定義:
#ifdef    _GNU_SOURCE
# define __USE_GNU    1
#endif

所以在我們程序的最開始位置, 定義了 _GNU_SOURCE 這個宏定義
--------------------- 
作者:watkins 
來源:CSDN 
原文:https://blog.csdn.net/watkinsong/article/details/28418911 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章