gpt4 book ai didi

c - 在 C 中创建周期性 Linux 线程的最佳方法是什么

转载 作者:太空宇宙 更新时间:2023-11-04 10:06:41 24 4
gpt4 key购买 nike

对于我的应用程序,我需要周期时间相对较短 (500 µs) 的精确周期性线程。
特别是应用程序是一个运行时系统 PLC .它的目的是运行由 PLC 用户开发的应用程序。这样的应用程序被组织成程序和周期性任务——每个任务都有自己的周期时间和优先级。
通常应用程序在具有实时操作系统的系统上运行(例如 vxWorks 或带有 RT 补丁的 Linux)。

目前周期性任务是通过clock_nanosleep实现的。不幸的是,clock_nanosleep 的实际休眠时间会被其他线程干扰——即使优先级较低。每秒一次, sleep 时间超过约 50 毫秒。我在 Debian 9.5、RaspberryPi 以及带有 Preemt-RT 的 ARM-Linux 上观察到了这一点。

这是一个示例,显示了这种行为:

#include <pthread.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>

typedef void* ThreadFun(void* param);

#define SCHEDULER_POLICY SCHED_FIFO
#define CLOCK CLOCK_MONOTONIC
#define INTERVAL_NS (10 * 1000 * 1000)

static long tickCnt = 0;

static long calcTimeDiff(struct timespec const* t1, struct timespec const* t2)
{
long diff = t1->tv_nsec - t2->tv_nsec;
diff += 1000000000 * (t1->tv_sec - t2->tv_sec);
return diff;
}

static void updateWakeTime(struct timespec* time)
{
uint64_t nanoSec = time->tv_nsec;
struct timespec currentTime;

clock_gettime(CLOCK, &currentTime);
while (calcTimeDiff(time, &currentTime) <= 0)
{
nanoSec = time->tv_nsec;
nanoSec += INTERVAL_NS;
time->tv_nsec = nanoSec % 1000000000;
time->tv_sec += nanoSec / 1000000000;
}
}

static void* tickThread(void *param)
{
struct timespec sleepStart;
struct timespec currentTime;
struct timespec wakeTime;
long sleepTime;
long wakeDelay;

clock_gettime(CLOCK, &wakeTime);
wakeTime.tv_sec += 2;
wakeTime.tv_nsec = 0;

while (1)
{
clock_gettime(CLOCK, &sleepStart);
clock_nanosleep(CLOCK, TIMER_ABSTIME, &wakeTime, NULL);
clock_gettime(CLOCK, &currentTime);
sleepTime = calcTimeDiff(&currentTime, &sleepStart);
wakeDelay = calcTimeDiff(&currentTime, &wakeTime);
if (wakeDelay > INTERVAL_NS)
{
printf("sleep req=%-ld.%-ld start=%-ld.%-ld curr=%-ld.%-ld sleep=%-ld delay=%-ld\n",
(long) wakeTime.tv_sec, (long) wakeTime.tv_nsec,
(long) sleepStart.tv_sec, (long) sleepStart.tv_nsec,
(long) currentTime.tv_sec, (long) currentTime.tv_nsec,
sleepTime, wakeDelay);
}
tickCnt += 1;
updateWakeTime(&wakeTime);
}
}

static void* workerThread(void *param)
{
while (1)
{
}
}

static int createThread(char const* funcName, ThreadFun* func, int prio)
{
pthread_t tid = 0;
pthread_attr_t threadAttr;
struct sched_param schedParam;

printf("thread create func=%s prio=%d\n", funcName, prio);

pthread_attr_init(&threadAttr);
pthread_attr_setschedpolicy(&threadAttr, SCHEDULER_POLICY);
pthread_attr_setinheritsched(&threadAttr, PTHREAD_EXPLICIT_SCHED);
schedParam.sched_priority = prio;
pthread_attr_setschedparam(&threadAttr, &schedParam);

if (pthread_create(&tid, &threadAttr, func, NULL) != 0)
{
return -1;
}

printf("thread created func=%s prio=%d\n", funcName, prio);
return 0;
}
#define CREATE_THREAD(func,prio) createThread(#func,func,prio)


int main(int argc, char*argv[])
{
int minPrio = sched_get_priority_min(SCHEDULER_POLICY);
int maxPrio = sched_get_priority_max(SCHEDULER_POLICY);
int prioRange = maxPrio - minPrio;

CREATE_THREAD(tickThread, maxPrio);
CREATE_THREAD(workerThread, minPrio + prioRange / 4);
sleep(10);
printf("%ld ticks\n", tickCnt);
}

我的代码示例有问题吗?

是否有更好(更可靠)的方法来创建周期性线程?

最佳答案

For my application I have the requirement of accurate periodic threads with relative low cycle times (500 µs)

可能要求太高了。 Linux 不是硬实时操作系统。

我建议使用更少的线程(也许是一个小的固定集合——只有 2 或 3 个,组织在 thread pool 中;参见 this 的解释,记住 RasberryPi3B+ 只有 4 个核心)。您可能更喜欢单线程(想想围绕事件循环的设计,灵感来自 continuation-passing style)。

您可能不需要定期 线程。你需要一些周期性的事件。它们都可能发生在同一个线程中。 (内核可能每 50 或 100 毫秒重新安排一次任务,即使它能够休眠更短的时间,并且如果任务被非常频繁地重新安排——例如每毫秒——,它们的安排就会有成本)。

所以仔细阅读time(7) .

考虑使用 timer_create(2) ,甚至更好 timerfd_create(2)poll(2) 周围的事件循环中使用.

在 RaspberryPi 上,您不会保证 500µs 延迟。这可能是不可能的(硬件可能不够强大,Linux 操作系统也不是硬实时的)。我觉得你的期望不合理。

关于c - 在 C 中创建周期性 Linux 线程的最佳方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52095008/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com