1. 在Linux 2.6上,怎么能够让一个线程每隔1ms起来运行一次?
我自己试用过以下两种方法,但结果不是很好,通过protype测试,大部分时间间隔是在1ms左右,但是总是有一部分时间间隔在好几个ms的级别,有的甚至是10ms以上。
(1)用settimer,interval为1000us;
(2)建立一个高优先级的线程,线程包括"需要执行的工作"和一个usleep来实现。这个usleep就是用来实现联系两次被调度上来的时间间隔是1ms。
所以,我想请教高手,
1.如何在用户层实现准确的1ms的timer或者是能够让一个线程能够每隔1ms起来执行一次?
2.在用户面,多线程的切换开销是多大?每个线程得到CPU后,执行的时间片是多长?
3.线程的调度策略是什么样的?能用pthread实现嘛?
在此谢过了!
11 个解决方案
#1
自顶!
#2
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#define PRINT_USEAGE { \
fprintf(stderr,"\n Usage: %s usec ",argv[0]); \
fprintf(stderr,"\n\n");\
}
int
main (int argc, char **argv)
{
unsigned int nTimeTestSec = 0; /* sec */
unsigned int nTimeTest = 0; /* usec */
struct timeval tvBegin;
struct timeval tvNow;
int ret = 0;
unsigned int nDelay = 0; /* usec */
fd_set rfds;
struct timeval tv;
int fd = 1;
int i = 0;
struct timespec req;
unsigned int delay[20] =
{ 500000, 100000, 50000, 10000, 1000, 900, 500, 100, 10, 1, 0 };
int nReduce = 0; /* 误差 */
#if 0
if (argc < 2)
{
PRINT_USEAGE;
exit (1);
}
nDelay = atoi (argv[1]);
#endif
fprintf (stderr, "%18s%12s%12s%12s\n", "function", "time(usec)", "realTime",
"reduce");
fprintf (stderr,
"-------------------------------------------------------------------\n");
for (i = 0; i < 20; i++)
{
if (delay[i] <= 0)
break;
nDelay = delay[i];
/* test usleep */
gettimeofday (&tvBegin, NULL);
ret = usleep (nDelay);
if (-1 == ret)
{
fprintf (stderr, " usleep error . errno=%d [%s]\n", errno,
strerror (errno));
}
gettimeofday (&tvNow, NULL);
nTimeTest =
(tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec -
tvBegin.tv_usec;
nReduce = nTimeTest - nDelay;
fprintf (stderr, "\t usleep %8u %8u %8d\n", nDelay, nTimeTest,nReduce);
/* test nanosleep */
gettimeofday (&tvBegin, NULL);
req.tv_sec = nDelay / 1000000;
req.tv_nsec = (nDelay % 1000000) * 1000;
ret = nanosleep (&req, NULL);
if (-1 == ret)
{
fprintf (stderr, "\t nanosleep %8u not support\n", nDelay);
}
else
{
gettimeofday (&tvNow, NULL);
nTimeTest =
(tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec -
tvBegin.tv_usec;
nReduce = nTimeTest - nDelay;
fprintf (stderr, "\t nanosleep %8u %8u %8d\n", nDelay,
nTimeTest, nReduce);
}
/* test select */
gettimeofday (&tvBegin, NULL);
FD_ZERO (&rfds);
FD_SET (fd, &rfds);
tv.tv_sec = 0;
tv.tv_usec = nDelay;
ret = select (0, NULL, NULL, NULL, &tv);
if (-1 == ret)
{
fprintf (stderr, " select error . errno=%d [%s]\n", errno,
strerror (errno));
}
gettimeofday (&tvNow, NULL);
nTimeTest =
(tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec -
tvBegin.tv_usec;
nReduce = nTimeTest - nDelay;
fprintf (stderr, "\t select %8u %8u %8d\n", nDelay, nTimeTest,
nReduce);
}
return 0;
}
这是测试预计延迟和实际延迟误差的一个小程序.
你可用测一下你的机器.
实际上1ms的延迟,不大好控制.
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#define PRINT_USEAGE { \
fprintf(stderr,"\n Usage: %s usec ",argv[0]); \
fprintf(stderr,"\n\n");\
}
int
main (int argc, char **argv)
{
unsigned int nTimeTestSec = 0; /* sec */
unsigned int nTimeTest = 0; /* usec */
struct timeval tvBegin;
struct timeval tvNow;
int ret = 0;
unsigned int nDelay = 0; /* usec */
fd_set rfds;
struct timeval tv;
int fd = 1;
int i = 0;
struct timespec req;
unsigned int delay[20] =
{ 500000, 100000, 50000, 10000, 1000, 900, 500, 100, 10, 1, 0 };
int nReduce = 0; /* 误差 */
#if 0
if (argc < 2)
{
PRINT_USEAGE;
exit (1);
}
nDelay = atoi (argv[1]);
#endif
fprintf (stderr, "%18s%12s%12s%12s\n", "function", "time(usec)", "realTime",
"reduce");
fprintf (stderr,
"-------------------------------------------------------------------\n");
for (i = 0; i < 20; i++)
{
if (delay[i] <= 0)
break;
nDelay = delay[i];
/* test usleep */
gettimeofday (&tvBegin, NULL);
ret = usleep (nDelay);
if (-1 == ret)
{
fprintf (stderr, " usleep error . errno=%d [%s]\n", errno,
strerror (errno));
}
gettimeofday (&tvNow, NULL);
nTimeTest =
(tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec -
tvBegin.tv_usec;
nReduce = nTimeTest - nDelay;
fprintf (stderr, "\t usleep %8u %8u %8d\n", nDelay, nTimeTest,nReduce);
/* test nanosleep */
gettimeofday (&tvBegin, NULL);
req.tv_sec = nDelay / 1000000;
req.tv_nsec = (nDelay % 1000000) * 1000;
ret = nanosleep (&req, NULL);
if (-1 == ret)
{
fprintf (stderr, "\t nanosleep %8u not support\n", nDelay);
}
else
{
gettimeofday (&tvNow, NULL);
nTimeTest =
(tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec -
tvBegin.tv_usec;
nReduce = nTimeTest - nDelay;
fprintf (stderr, "\t nanosleep %8u %8u %8d\n", nDelay,
nTimeTest, nReduce);
}
/* test select */
gettimeofday (&tvBegin, NULL);
FD_ZERO (&rfds);
FD_SET (fd, &rfds);
tv.tv_sec = 0;
tv.tv_usec = nDelay;
ret = select (0, NULL, NULL, NULL, &tv);
if (-1 == ret)
{
fprintf (stderr, " select error . errno=%d [%s]\n", errno,
strerror (errno));
}
gettimeofday (&tvNow, NULL);
nTimeTest =
(tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec -
tvBegin.tv_usec;
nReduce = nTimeTest - nDelay;
fprintf (stderr, "\t select %8u %8u %8d\n", nDelay, nTimeTest,
nReduce);
}
return 0;
}
这是测试预计延迟和实际延迟误差的一个小程序.
你可用测一下你的机器.
实际上1ms的延迟,不大好控制.
#3
### o-1.txt ---
1.如何在用户层实现准确的1ms的timer或者是能够让一个线程能够每隔1ms起来执行一次?
不能,如果不特别高要求是可以的。
2.在用户面,多线程的切换开销是多大?每个线程得到CPU后,执行的时间片是多长?
a.开销很小,因为调度程序采用O(1)算法;b.执行时间片开始默认20ms,根据调度算法策略和优先级等计算该时间总是变化的。
3.线程的调度策略是什么样的?能用pthread实现嘛?
a.线程策略就是进程策略;b.估计很难没有试过
建议:a.可以试试内核的软中断;b.如果对时间特别要求可以是设置进程内核调度策略为SCHED_FIFO、SCHED_RR,这两个都是实时的,还可以看看关于内核抢占的资料,最好用最新的kernel;
1.如何在用户层实现准确的1ms的timer或者是能够让一个线程能够每隔1ms起来执行一次?
不能,如果不特别高要求是可以的。
2.在用户面,多线程的切换开销是多大?每个线程得到CPU后,执行的时间片是多长?
a.开销很小,因为调度程序采用O(1)算法;b.执行时间片开始默认20ms,根据调度算法策略和优先级等计算该时间总是变化的。
3.线程的调度策略是什么样的?能用pthread实现嘛?
a.线程策略就是进程策略;b.估计很难没有试过
建议:a.可以试试内核的软中断;b.如果对时间特别要求可以是设置进程内核调度策略为SCHED_FIFO、SCHED_RR,这两个都是实时的,还可以看看关于内核抢占的资料,最好用最新的kernel;
#4
多谢,上面两位的回复,非常好,我会按着这个方向再做一些原型去测试,有收获会和大家一起来分享一下。
针对我的问题“如何在用户层实现准确的1ms的timer或者是能够让一个线程能够每隔1ms起来执行一次?”
我可以更改如下:不一定要非常精确,在1ms左右就行,只要不出现此线程被调度上来的时间间隔是好几个ms甚至10ms以上。
多谢各位!
针对我的问题“如何在用户层实现准确的1ms的timer或者是能够让一个线程能够每隔1ms起来执行一次?”
我可以更改如下:不一定要非常精确,在1ms左右就行,只要不出现此线程被调度上来的时间间隔是好几个ms甚至10ms以上。
多谢各位!
#5
补充就是在kernel编译的HZ值设置大些
如HZ=2000或者更大点,但是不是越大越好,最好根据自己的硬件调试最值
可以提高进程调度精确度
如HZ=2000或者更大点,但是不是越大越好,最好根据自己的硬件调试最值
可以提高进程调度精确度
#6
nanosleep试试,开一个线程
死循环
执行一下程序延时一下
死循环
执行一下程序延时一下
#7
帮顶
#8
stTimeVal.tv_sec = 0;
stTimeVal.tv_usec = 1;
select(FD_SIZE, 0, 0,0, &stTimeVal );
stTimeVal.tv_usec = 1;
select(FD_SIZE, 0, 0,0, &stTimeVal );
#9
或者getCpuTick
#10
帮顶,对时间片问题一直是个困饶
#11
不知道你用的什么架构的芯片,不管怎么说,要想在一般的LINUX下实现1ms的分辩率是非常困难的,可以有两个途径,但首先你得基于2。6得内核,而且调度机制一定要设置成SCHED_RR。
1。如果你的芯片速度不够,操作系统时钟是10ms得话,也就是1jiffy=10ms,你不可能达到1ms的分辩率的,只有自己加一个实时时钟(RTC),以提供小于1ms的分辩率,这样才能满足你的需求
2。如果你的芯片主频够高,你可以设置1jiffy=1ms,这也是2。6的配置,可以基本满足你的要求,但是你想更精确一点,需要更高精度的时钟,如果设置为1jiffy=0。5ms,可能系统忙于相应中断,整个性能会下降。
对于你说的有时候可能有10ms或更大的值,这是LINUX对于实时性支持的局限性,由于请求调页机制的存在就会引入这么大的误差,你可以考虑换用实时Linux版本,比如RTLinux试试。
1。如果你的芯片速度不够,操作系统时钟是10ms得话,也就是1jiffy=10ms,你不可能达到1ms的分辩率的,只有自己加一个实时时钟(RTC),以提供小于1ms的分辩率,这样才能满足你的需求
2。如果你的芯片主频够高,你可以设置1jiffy=1ms,这也是2。6的配置,可以基本满足你的要求,但是你想更精确一点,需要更高精度的时钟,如果设置为1jiffy=0。5ms,可能系统忙于相应中断,整个性能会下降。
对于你说的有时候可能有10ms或更大的值,这是LINUX对于实时性支持的局限性,由于请求调页机制的存在就会引入这么大的误差,你可以考虑换用实时Linux版本,比如RTLinux试试。
#1
自顶!
#2
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#define PRINT_USEAGE { \
fprintf(stderr,"\n Usage: %s usec ",argv[0]); \
fprintf(stderr,"\n\n");\
}
int
main (int argc, char **argv)
{
unsigned int nTimeTestSec = 0; /* sec */
unsigned int nTimeTest = 0; /* usec */
struct timeval tvBegin;
struct timeval tvNow;
int ret = 0;
unsigned int nDelay = 0; /* usec */
fd_set rfds;
struct timeval tv;
int fd = 1;
int i = 0;
struct timespec req;
unsigned int delay[20] =
{ 500000, 100000, 50000, 10000, 1000, 900, 500, 100, 10, 1, 0 };
int nReduce = 0; /* 误差 */
#if 0
if (argc < 2)
{
PRINT_USEAGE;
exit (1);
}
nDelay = atoi (argv[1]);
#endif
fprintf (stderr, "%18s%12s%12s%12s\n", "function", "time(usec)", "realTime",
"reduce");
fprintf (stderr,
"-------------------------------------------------------------------\n");
for (i = 0; i < 20; i++)
{
if (delay[i] <= 0)
break;
nDelay = delay[i];
/* test usleep */
gettimeofday (&tvBegin, NULL);
ret = usleep (nDelay);
if (-1 == ret)
{
fprintf (stderr, " usleep error . errno=%d [%s]\n", errno,
strerror (errno));
}
gettimeofday (&tvNow, NULL);
nTimeTest =
(tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec -
tvBegin.tv_usec;
nReduce = nTimeTest - nDelay;
fprintf (stderr, "\t usleep %8u %8u %8d\n", nDelay, nTimeTest,nReduce);
/* test nanosleep */
gettimeofday (&tvBegin, NULL);
req.tv_sec = nDelay / 1000000;
req.tv_nsec = (nDelay % 1000000) * 1000;
ret = nanosleep (&req, NULL);
if (-1 == ret)
{
fprintf (stderr, "\t nanosleep %8u not support\n", nDelay);
}
else
{
gettimeofday (&tvNow, NULL);
nTimeTest =
(tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec -
tvBegin.tv_usec;
nReduce = nTimeTest - nDelay;
fprintf (stderr, "\t nanosleep %8u %8u %8d\n", nDelay,
nTimeTest, nReduce);
}
/* test select */
gettimeofday (&tvBegin, NULL);
FD_ZERO (&rfds);
FD_SET (fd, &rfds);
tv.tv_sec = 0;
tv.tv_usec = nDelay;
ret = select (0, NULL, NULL, NULL, &tv);
if (-1 == ret)
{
fprintf (stderr, " select error . errno=%d [%s]\n", errno,
strerror (errno));
}
gettimeofday (&tvNow, NULL);
nTimeTest =
(tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec -
tvBegin.tv_usec;
nReduce = nTimeTest - nDelay;
fprintf (stderr, "\t select %8u %8u %8d\n", nDelay, nTimeTest,
nReduce);
}
return 0;
}
这是测试预计延迟和实际延迟误差的一个小程序.
你可用测一下你的机器.
实际上1ms的延迟,不大好控制.
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#define PRINT_USEAGE { \
fprintf(stderr,"\n Usage: %s usec ",argv[0]); \
fprintf(stderr,"\n\n");\
}
int
main (int argc, char **argv)
{
unsigned int nTimeTestSec = 0; /* sec */
unsigned int nTimeTest = 0; /* usec */
struct timeval tvBegin;
struct timeval tvNow;
int ret = 0;
unsigned int nDelay = 0; /* usec */
fd_set rfds;
struct timeval tv;
int fd = 1;
int i = 0;
struct timespec req;
unsigned int delay[20] =
{ 500000, 100000, 50000, 10000, 1000, 900, 500, 100, 10, 1, 0 };
int nReduce = 0; /* 误差 */
#if 0
if (argc < 2)
{
PRINT_USEAGE;
exit (1);
}
nDelay = atoi (argv[1]);
#endif
fprintf (stderr, "%18s%12s%12s%12s\n", "function", "time(usec)", "realTime",
"reduce");
fprintf (stderr,
"-------------------------------------------------------------------\n");
for (i = 0; i < 20; i++)
{
if (delay[i] <= 0)
break;
nDelay = delay[i];
/* test usleep */
gettimeofday (&tvBegin, NULL);
ret = usleep (nDelay);
if (-1 == ret)
{
fprintf (stderr, " usleep error . errno=%d [%s]\n", errno,
strerror (errno));
}
gettimeofday (&tvNow, NULL);
nTimeTest =
(tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec -
tvBegin.tv_usec;
nReduce = nTimeTest - nDelay;
fprintf (stderr, "\t usleep %8u %8u %8d\n", nDelay, nTimeTest,nReduce);
/* test nanosleep */
gettimeofday (&tvBegin, NULL);
req.tv_sec = nDelay / 1000000;
req.tv_nsec = (nDelay % 1000000) * 1000;
ret = nanosleep (&req, NULL);
if (-1 == ret)
{
fprintf (stderr, "\t nanosleep %8u not support\n", nDelay);
}
else
{
gettimeofday (&tvNow, NULL);
nTimeTest =
(tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec -
tvBegin.tv_usec;
nReduce = nTimeTest - nDelay;
fprintf (stderr, "\t nanosleep %8u %8u %8d\n", nDelay,
nTimeTest, nReduce);
}
/* test select */
gettimeofday (&tvBegin, NULL);
FD_ZERO (&rfds);
FD_SET (fd, &rfds);
tv.tv_sec = 0;
tv.tv_usec = nDelay;
ret = select (0, NULL, NULL, NULL, &tv);
if (-1 == ret)
{
fprintf (stderr, " select error . errno=%d [%s]\n", errno,
strerror (errno));
}
gettimeofday (&tvNow, NULL);
nTimeTest =
(tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec -
tvBegin.tv_usec;
nReduce = nTimeTest - nDelay;
fprintf (stderr, "\t select %8u %8u %8d\n", nDelay, nTimeTest,
nReduce);
}
return 0;
}
这是测试预计延迟和实际延迟误差的一个小程序.
你可用测一下你的机器.
实际上1ms的延迟,不大好控制.
#3
### o-1.txt ---
1.如何在用户层实现准确的1ms的timer或者是能够让一个线程能够每隔1ms起来执行一次?
不能,如果不特别高要求是可以的。
2.在用户面,多线程的切换开销是多大?每个线程得到CPU后,执行的时间片是多长?
a.开销很小,因为调度程序采用O(1)算法;b.执行时间片开始默认20ms,根据调度算法策略和优先级等计算该时间总是变化的。
3.线程的调度策略是什么样的?能用pthread实现嘛?
a.线程策略就是进程策略;b.估计很难没有试过
建议:a.可以试试内核的软中断;b.如果对时间特别要求可以是设置进程内核调度策略为SCHED_FIFO、SCHED_RR,这两个都是实时的,还可以看看关于内核抢占的资料,最好用最新的kernel;
1.如何在用户层实现准确的1ms的timer或者是能够让一个线程能够每隔1ms起来执行一次?
不能,如果不特别高要求是可以的。
2.在用户面,多线程的切换开销是多大?每个线程得到CPU后,执行的时间片是多长?
a.开销很小,因为调度程序采用O(1)算法;b.执行时间片开始默认20ms,根据调度算法策略和优先级等计算该时间总是变化的。
3.线程的调度策略是什么样的?能用pthread实现嘛?
a.线程策略就是进程策略;b.估计很难没有试过
建议:a.可以试试内核的软中断;b.如果对时间特别要求可以是设置进程内核调度策略为SCHED_FIFO、SCHED_RR,这两个都是实时的,还可以看看关于内核抢占的资料,最好用最新的kernel;
#4
多谢,上面两位的回复,非常好,我会按着这个方向再做一些原型去测试,有收获会和大家一起来分享一下。
针对我的问题“如何在用户层实现准确的1ms的timer或者是能够让一个线程能够每隔1ms起来执行一次?”
我可以更改如下:不一定要非常精确,在1ms左右就行,只要不出现此线程被调度上来的时间间隔是好几个ms甚至10ms以上。
多谢各位!
针对我的问题“如何在用户层实现准确的1ms的timer或者是能够让一个线程能够每隔1ms起来执行一次?”
我可以更改如下:不一定要非常精确,在1ms左右就行,只要不出现此线程被调度上来的时间间隔是好几个ms甚至10ms以上。
多谢各位!
#5
补充就是在kernel编译的HZ值设置大些
如HZ=2000或者更大点,但是不是越大越好,最好根据自己的硬件调试最值
可以提高进程调度精确度
如HZ=2000或者更大点,但是不是越大越好,最好根据自己的硬件调试最值
可以提高进程调度精确度
#6
nanosleep试试,开一个线程
死循环
执行一下程序延时一下
死循环
执行一下程序延时一下
#7
帮顶
#8
stTimeVal.tv_sec = 0;
stTimeVal.tv_usec = 1;
select(FD_SIZE, 0, 0,0, &stTimeVal );
stTimeVal.tv_usec = 1;
select(FD_SIZE, 0, 0,0, &stTimeVal );
#9
或者getCpuTick
#10
帮顶,对时间片问题一直是个困饶
#11
不知道你用的什么架构的芯片,不管怎么说,要想在一般的LINUX下实现1ms的分辩率是非常困难的,可以有两个途径,但首先你得基于2。6得内核,而且调度机制一定要设置成SCHED_RR。
1。如果你的芯片速度不够,操作系统时钟是10ms得话,也就是1jiffy=10ms,你不可能达到1ms的分辩率的,只有自己加一个实时时钟(RTC),以提供小于1ms的分辩率,这样才能满足你的需求
2。如果你的芯片主频够高,你可以设置1jiffy=1ms,这也是2。6的配置,可以基本满足你的要求,但是你想更精确一点,需要更高精度的时钟,如果设置为1jiffy=0。5ms,可能系统忙于相应中断,整个性能会下降。
对于你说的有时候可能有10ms或更大的值,这是LINUX对于实时性支持的局限性,由于请求调页机制的存在就会引入这么大的误差,你可以考虑换用实时Linux版本,比如RTLinux试试。
1。如果你的芯片速度不够,操作系统时钟是10ms得话,也就是1jiffy=10ms,你不可能达到1ms的分辩率的,只有自己加一个实时时钟(RTC),以提供小于1ms的分辩率,这样才能满足你的需求
2。如果你的芯片主频够高,你可以设置1jiffy=1ms,这也是2。6的配置,可以基本满足你的要求,但是你想更精确一点,需要更高精度的时钟,如果设置为1jiffy=0。5ms,可能系统忙于相应中断,整个性能会下降。
对于你说的有时候可能有10ms或更大的值,这是LINUX对于实时性支持的局限性,由于请求调页机制的存在就会引入这么大的误差,你可以考虑换用实时Linux版本,比如RTLinux试试。