【问题标题】:What is the nice value of a thread after pthread_create()?pthread_create() 之后线程的好处是什么?
【发布时间】:2021-11-29 18:55:29
【问题描述】:

我正在使用 libx264 库将视频数据压缩到... x264。

我使用默认设置让库根据需要创建尽可能多(少)的线程:

param.i_threads = X264_THREADS_AUTO;

这在我有 64 个处理器(2 个 CPU,每个 CPU 有 16 个内核和英特尔线程)的服务器上效果很好。它实际上将使用大约 5 个线程。

但是,在运行该软件的嵌入式计算机上,我只有 4 个 CPU。它是 Xeon,所以那里没有太多问题,但不知何故它会阻止 USB 端口正常工作。我们正在从那个 USB 端口接收数据,当 4 个 CPU 以大约 100% 的速度使用时,libx264 代码非常糟糕地接管了整个计算机。

我在想两种解决方案,使用 3 作为最大线程数:

param.i_threads = 3;

或者让那些 libx264 线程有一个(很多)更高的 nice 值,这样在该计算机上运行的其他东西就不会被阻塞(即 CPU 更好地共享;其他东西不使用太多 CPU,它通常低于10%)。

但是,我无法控制 libx264 库如何创建线程,并且想知道在调用创建线程的 libx264 函数之前更改 nice 值是否对我有用,因此这些线程使用它不错的价值,像这样:

nice(10);
...call libx264 functions...
nice(0);

使这些线程使用 +10 的良好值的意愿?从我在pthread_create() 手册页中可以看到,它并没有明确说明线程继承父线程的nice 值...


注意 1: 我知道这个问题不太可能是因为 USB 端口可能正在与视频采集卡争夺 DMA……如果是这种情况,我们'显然不会仅仅通过改变进程的优先级来解决任何问题。我想先试试那个软解决方案。

虽然我可以将 USB 端口移到另一台计算机上,但数据会通过网络传输,这很可能会出现类似的硬件冲突问题。


注意 2: 我不想重新编译 libx264 并更改该代码。这超出了我的项目范围。

【问题讨论】:

  • 想知道它是否可行”。当然,这可以通过尝试来回答或至少进行调查。运行代码,看看线程的nice值?
  • Niceness 继承自父进程/线程,AFAIK。考虑到它们的 TID(您可以在系统调用中将其用作 PID),您始终可以在它们启动后 renice(2) 线程,提高它们的友好度。您甚至可以完全从进程外部执行此操作,手动使用 tophtopps + renice(1),作为一次性实验,无需更改任何代码。
  • 请记住,在没有 root 权限的情况下,您只能使事物 more nice,而不能将 nice 降为 0(niceness 越低,优先级越高)。因此,为了让一些线程更友好,您可以编写一个使用 nice(2) 的包装函数,然后对 x264 函数进行尾调用,这样父线程就不必改变自己的友好度。从该线程开始的任何更多线程 x264 将至少与此一样好。
  • 回复:你的实际问题;我猜想让所有超线程保持忙碌可能会消耗大量内存带宽/缓存占用空间。仅让 x264 每个 物理 内核启动一个线程,但为 DMA 留出更多带宽,您可能不会看到吞吐量下降太多。以及在必要时为 CPU 密集型 USB 设备腾出内核。 (我怀疑下半部分中断处理程序的优先级甚至低于nice(-19),但如果涉及其他用户空间进程,那么nice 可能很重要..)
  • 你的问题的答案:“那会让那些线程使用一个不错的 +10 值吗?”。您可以通过编写一个简单的测试程序并运行它来确认这一点,使用htop 或任何其他工具来检查它的好坏。不知道这里还有什么要说的。进程/线程的好处是整个互联网都在谈论令人作呕的事情......

标签: c linux multithreading intel nice


【解决方案1】:

首先,X264 库会在您使用x264_encoder_open() 打开句柄时创建线程。这是唯一需要更新 nice 值的函数。

正如 Peter Cordes 在评论中指出的那样,以下方法仅在您以 root 身份运行时才有效(通常不建议这样做,即使对于守护进程也是如此):

nice(10);
...call libx264 functions...
nice(0);

这也是错误的,因为 nice(0) 只是返回当前的 nice 值。正确的调用是nice(-10)

一种解决方案是授予进程权限以成为 root,当尝试执行 nice(-10) 时,在之前成为 root 并在之后删除权限。

// change nice(2) to non-preemptive
int inc_nice = 10;
nice(inc_nice);

// create the X264 threads
x264_encoder_open(&params);

// restore the nice value
uid_t user(getuid());
seteuid(0);
nice(-inc_nice);
seteuid(user);

请注意,如果您使用多个线程运行,则此代码不安全。在seteuid(0) 返回时,您的其他线程将具有root 权限。假设您的应用程序是安全的,这应该不是什么大问题,但仍然需要牢记。

要让 systemd 服务有权成为 root,您需要这些东西:

  1. 这假设您使用用户和组选项在启动时删除权限。如果您的守护进程以 root 身份运行,那么您甚至不需要特殊处理。您只需拨打nice(-10) 即可。

    以下内容供 Debian 上的 Web 服务器使用:

     User=www-data
     Group=www-data
    
  2. 赋予进程特权:

    要么将NoNewPrivileges 设置为 false(或者不包括它,因为这是默认设置):

     NoNewPrivileges=false
    
  3. 给进程选择成为root的选项:

    您需要确保进程所有者是 root 并且设置了 's' 标志(也称为 set user on execution):

     chown root /usr/sbin/my-app
     chmod u+s /usr/sbin/my-app
    

    在大多数情况下,如果您使用 Linux 系统的标准打包程序,则安装在 /usr/sbin 下的文件将已经归 root 所有。但是,默认情况下未设置“s”标志。创建 Debian 软件包时,您可以添加 debian/rules 文件,其中包含以下内容:

     override_dh_fixperms:
         dh_fixperms
         chmod u+s debian/project-name/usr/sbin/my-app
    

    注意:rules 文件是一个 makefile,因此缩进应该是一个制表符。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-08
    • 1970-01-01
    • 2013-01-13
    • 1970-01-01
    • 2012-01-12
    相关资源
    最近更新 更多