Unix/C/C++进阶--线程 pthread_creat() return 1失败

文章详细介绍了在Unix/Linux环境下使用pthread_create创建线程时遇到的EPERM错误,通常由于资源不足或系统限制导致。讨论了线程和进程的最大数量、查看系统线程状态的方法,并提供了两种解决方案:修改service配置和调整rt_runtime_us文件。
摘要由CSDN通过智能技术生成

1 介绍

1.1 man pthread_create

PTHREAD_CREATE(3)                                                                     Linux Programmer's Manual                                                                     PTHREAD_CREATE(3)

NAME
       pthread_create - create a new thread

SYNOPSIS
       #include <pthread.h>

       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

       Compile and link with -pthread.

DESCRIPTION
       The pthread_create() function starts a new thread in the calling process.  The new thread starts execution by invoking start_routine(); arg is passed as the sole argument of start_routine().

       The new thread terminates in one of the following ways:

       * It calls pthread_exit(3), specifying an exit status value that is available to another thread in the same process that calls pthread_join(3).

       * It returns from start_routine().  This is equivalent to calling pthread_exit(3) with the value supplied in the return statement.

       * It is canceled (see pthread_cancel(3)).

       * Any of the threads in the process calls exit(3), or the main thread performs a return from main().  This causes the termination of all threads in the process.

       The  attr  argument  points  to  a  pthread_attr_t  structure  whose contents are used at thread creation time to determine attributes for the new thread; this structure is initialized using
       pthread_attr_init(3) and related functions.  If attr is NULL, then the thread is created with default attributes.

       Before returning, a successful call to pthread_create() stores the ID of the new thread in the buffer pointed to by thread; this identifier is used to refer to the thread in subsequent calls
       to other pthreads functions.

       The  new  thread  inherits a copy of the creating thread's signal mask (pthread_sigmask(3)).  The set of pending signals for the new thread is empty (sigpending(2)).  The new thread does not
       inherit the creating thread's alternate signal stack (sigaltstack(2)).

       The new thread inherits the calling thread's floating-point environment (fenv(3)).

       The initial value of the new thread's CPU-time clock is 0 (see pthread_getcpuclockid(3)).

   Linux-specific details
       The new thread inherits copies of the calling thread's capability sets (see capabilities(7)) and CPU affinity mask (see sched_setaffinity(2)).

RETURN VALUE
       On success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined.

ERRORS
       EAGAIN Insufficient resources to create another thread.

       EAGAIN A system-imposed limit on the number of threads was encountered.  There are a number of limits that may trigger this error:  the  RLIMIT_NPROC  soft  resource  limit  (set  via  setr‐
              limit(2)),  which  limits  the  number  of processes and threads for a real user ID, was reached; the kernel's system-wide limit on the number of processes and threads, /proc/sys/ker‐
              nel/threads-max, was reached (see proc(5)); or the maximum number of PIDs, /proc/sys/kernel/pid_max, was reached (see proc(5)).

       EINVAL Invalid settings in attr.

1.2 一般失败原因

EAGAIN 创建线程时,资源数不足,或者是遇到了系统对线程数量的限制
EINVAL arrt 中使用了无效参数
EPERM 系统不允许设置调度策略 和 在attr中使用特定的参数

EPERM的定义,在 erron.h 头文件中的定义,就是1

1.3 最大进程/线程数(理论)

以imx6为例:

cat /proc/sys/kernel/pid_max
32768

可以使用ulimit –u 查看系统限制某用户最大可以运行多少线程max_user_process

ulimit -u 65535
sysctl -w kernel.pid_max=65535

1.3 最大进程/线程数(实际)

理论上linux 上最大线程数是 = 总虚拟内存(用户空间) / 线程栈大小;

一般32bit PC机系统上,进程空间是4G,其中0—3G 是用户空间,3G —4G 是内核空间,所以理论上最大线程数 = 3*1024/ 8M = 384个,考虑系统主线程占用情况,故可创建的最大线程大概为 384 个;如何进程或者线程占用的栈空间小于8M,实际能创建更多的进程/线程。

1.4 查看Linux实际运行的总线程数

ps -eL | wc –l
176

1.5 查看运行的进程

所有:
ps aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.3   5480  3708 ?        Ss   May20   0:04 /sbin/init
root         2  0.0  0.0      0     0 ?        S    May20   0:00 [kthreadd]
root         3  0.1  0.0      0     0 ?        R    May20   2:32 [ksoftirqd/0]
root         4  0.1  0.0      0     0 ?        S    May20   1:48 [ktimersoftd/0]
root         6  0.0  0.0      0     0 ?        S<   May20   0:00 [kworker/0:0H]
root         7  0.0  0.0      0     0 ?        S    May20   0:00 [kworker/u8:0]
root         8  0.0  0.0      0     0 ?        S    May20   0:36 [rcu_preempt]
root         9  0.0  0.0      0     0 ?        S    May20   0:00 [rcu_sched]
root        10  0.0  0.0      0     0 ?        S    May20   0:00 [rcu_bh]

筛选:
ps aux | grep 某进程名

root     18741  0.0  0.2   3832  2248 pts/0    Sl   07:41   0:00 ./ubase

1.6 查看进程信息

打印信息中Threads后面就是线程数量。

cat /proc/{pid}/status

Name:   ubase
State:  S (sleeping)
Tgid:   18741
Ngid:   0
Pid:    18741
PPid:   9740
TracerPid:      0
Uid:    0       0       0       0
Gid:    0       0       0       0
FDSize: 256
Groups: 0
VmPeak:     3832 kB
VmSize:     3832 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM:      2248 kB
VmRSS:      2248 kB
VmData:      716 kB
VmStk:       136 kB
VmExe:        92 kB
VmLib:      2512 kB
VmPTE:        14 kB
VmPMD:         0 kB
VmSwap:        0 kB
Threads:        2
SigQ:   0/5431
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000180000000
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
Cpus_allowed:   f
Cpus_allowed_list:      0-3
Mems_allowed:   1
Mems_allowed_list:      0
voluntary_ctxt_switches:        206
nonvoluntary_ctxt_switches:     18

1.7 top -H 一行显示一个线程

top -H
top - 07:54:14 up 1 day,  2:29,  1 user,  load average: 0.42, 0.23, 0.17
Threads: 176 total,   1 running, 175 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.7 us,  2.0 sy,  0.0 ni, 97.3 id,  0.0 wa,  0.0 hi,  0.1 si,  0.0 st
KiB Mem :  1023424 total,   664420 free,   162856 used,   196148 buff/cache
KiB Swap:        0 total,        0 free,        0 used.   823124 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
27866 root      20   0    5068   2344   1816 R  1.3  0.2   0:00.32 top
    1 root      20   0    5480   3708   2552 S  0.0  0.4   0:04.75 systemd
    2 root      20   0       0      0      0 S  0.0  0.0   0:00.01 kthreadd
    3 root      20   0       0      0      0 S  0.0  0.0   2:33.51 ksoftirqd/0
    4 root      -2   0       0      0      0 S  0.0  0.0   1:49.58 ktimersoftd/0
    6 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 kworker/0:0H
    7 root      20   0       0      0      0 S  0.0  0.0   0:00.07 kworker/u8:0
    8 root      -2   0       0      0      0 S  0.0  0.0   0:37.30 rcu_preempt
    9 root      -2   0       0      0      0 S  0.0  0.0   0:00.00 rcu_sched
   10 root      -2   0       0      0      0 S  0.0  0.0   0:00.00 rcu_bh
   11 root      -2   0       0      0      0 S  0.0  0.0   0:00.00 rcub/0
   12 root      -2   0       0      0      0 S  0.0  0.0   0:49.81 rcuc/0
   13 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kclksetdelayd
   14 root      rt   0       0      0      0 S  0.0  0.0   0:00.00 posixcputmr/0
   15 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kcmosdelayd
   16 root      rt   0       0      0      0 S  0.0  0.0   0:07.62 migration/0
   17 root      rt   0       0      0      0 S  0.0  0.0   0:07.22 migration/1
   18 root      -2   0       0      0      0 S  0.0  0.0   1:13.46 rcuc/1

1.8 top -Hp pid 查看进程信息(资源暂用、线程状态)

 top -Hp 18741

top - 07:57:10 up 1 day,  2:32,  1 user,  load average: 0.09, 0.16, 0.14
Threads:   2 total,   0 running,   2 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.7 us,  2.5 sy,  0.0 ni, 96.6 id,  0.2 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  1023424 total,   664040 free,   163208 used,   196176 buff/cache
KiB Swap:        0 total,        0 free,        0 used.   822776 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
18741 root      20   0    3832   2248   2100 S  0.0  0.2   0:00.03 ubase
18743 root      -2   0    3832   2248   2100 S  0.0  0.2   0:00.00 Can0_Motor

1.9 ulimits -s 查看默认栈空间

8192KB(8M)

ulimits -s
8192

2 问题描述

在Linux系统 ubuntu16.04 中,ssh进去,root下,运行进程,pthread_create实时线程创建失败,返回1。

3 问题分析

EPERM的定义,在 erron.h 头文件中的定义,就是1。从解释看,就是说没有权限来设置调度策略及参数定义。
systemd默认将ssh连接放到一个非rt组中,如果试图ssh并运行FIFO/RR任务,它将不起作用。您需要将shell移到允许优先级调度的默认cpu:/ group中。
cgclass -g cpu:/ $$
如果你把ControlGroup=cpu:/放在[service]下,你的systemd单元文件可以启动你的服务并获得优先级调度。

from:https://github.com/coreos/bugs/issues/410

what may or may not be very related, systemd defaults put ssh connections into a non-RT cgroup. if you're trying to ssh in and run FIFO/RR tasks, it just won't work. you need to move your shell into the default cpu:/ group which does permit priority scheduling.

cgclassify -g cpu:/ $$

your systemd unit file can start your service and get priority scheduling if you put ControlGroup=cpu:/ under [Service]

4 解决方案

4.1 service 中删除Delegate=yes

cat lib/systemd/system/user@.service
将Delegate=yes注释掉,就可以了。

4.2 向rt_runtime_us文件中写入数据

向rt_runtime_us文件中写入数据950000。
echo 950000 > /sys/fs/cgroup/cpu,cpuacct/user.slice/cpu.rt_runtime_us
echo 950000 > /sys/fs/cgroup/cpu,cpuacct/user.slice/user-0.slice/cpu.rt_runtime_us
echo 950000 > /sys/fs/cgroup/cpu,cpuacct/user.slice/user-0.slice/session-c1.scope/cpu.rt_runtime_us

参考

1、
2、pthread_create priority thread returns EPERM when run as root
3、Linux pthread_creat() 创建线程失败问题总结
4、Linux创建实时线程失败 (pthread_create SCHED_RR 失败)
5、pthread_create返回值

要使用`pthread_create`函数创建线程,你需要包含`pthread.h`头文件,并按照以下方式调用该函数: ```c #include <stdio.h> #include <pthread.h> void *thread_func(void *arg) { // 线程执行的代码 printf("Hello from new thread!\n"); return NULL; } int main() { pthread_t thread; int ret; // 创建线程 ret = pthread_create(&thread, NULL, thread_func, NULL); if (ret != 0) { printf("Failed to create thread: %d\n", ret); return 1; } // 等待线程结束 ret = pthread_join(thread, NULL); if (ret != 0) { printf("Failed to join thread: %d\n", ret); return 1; } printf("Thread finished.\n"); return 0; } ``` 在上面的代码中,定义了一个新线程的入口函数`thread_func`。然后,在`main`函数中,使用`pthread_create`函数创建一个新线程,并将线程函数`thread_func`作为参数传递给它。`pthread_create`函数的第一个参数是一个指向线程标识符的指针,用于存储新线程的ID。第二个参数是线程属性,这里我们传递了NULL表示使用默认属性。第三个参数是线程函数的指针,最后一个参数是传递给线程函数的参数。 创建线程成功后,我们使用`pthread_join`函数等待新线程的结束。`pthread_join`函数的第一个参数是要等待的线程ID,第二个参数是指向线程返回值的指针,我们在这里传递了NULL,因为在`thread_func`中没有返回值。 最后,我们输出一条消息表示主线程的执行已经结束。 希望这个例子能帮助到你!如果还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

worthsen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值