linux 中应该使用哪个时钟进行进程间通信?
Which clock should be used for inter process communication in linux?
我已经实现了两个带有两个消息队列的单线程进程 A 和 B [发送和接收的单独队列]。进程 A 将消息发送给 B,并在接收队列中等待回复。
我想从进程 A 发送一个时间戳到进程 B。如果进程 B 在 10 秒后收到消息,我想从进程 B 向 A 发送一个错误字符串。
精度应该以毫秒为单位。
在我使用的进程A中,
struct timespec msg_dispatch_time;
clock_gettime(CLOCK_REALTIME, &msg_dispatch_time);
:
:
add_timestamp_in_msg(msg, msg_dispatch_time);
:
if (msgsnd(msqid, msg, sizeof(msg), msgflg) == -1)
perror("msgop: msgsnd failed");
进程B中,
struct timespec msg_dispatch_time;
struct timespec msg_receive_time;
:
clock_gettime(CLOCK_REALTIME, &msg_received_time);
:
if( !(time_diff(msg_received_time, msg_dispatch_time) >= 10 ))
msgsnd(msqid, &sbuf, buf_length, msg_flag)
else
{
/*send the error string.*/
//msgsnd(msgid,)
}
我的问题是,
1) 如何在这里写一个 time_diff 函数以毫秒精度与 10 秒进行比较?
if( !(time_diff(msg_received_time, msg_dispatch_time) >= 10 ))
/********Existing time diff code******************/
long int time_diff (struct timeval time1, struct timeval time2)
{
struct timeval diff,
if (time1.tv_usec < time2.tv_usec) {
time1.tv_usec += 1000000;
time1.tv_sec--;
}
diff.tv_usec = time1.tv_usec - time2.tv_usec;
diff.tv_sec = time1.tv_sec - time2.tv_sec;
return diff.tv_sec; //return the diff in second
}
2) clock_gettime 是否可以在同一系统中跨进程使用?
如果您希望继续使用 struct timespec
类型,那么我建议使用 struct timespec
类型的等效 difftime()
,即
double difftimespec(const struct timespec after, const struct timespec before)
{
return (double)(after.tv_sec - before.tv_sec)
+ (double)(after.tv_nsec - before.tv_nsec) / 1000000000.0;
}
但是,我认为对于您的整体用例存在更好的选择。
如果您对程序运行到 2242 年感到满意,您可以使用 64 位带符号整数来保存自纪元以来的纳秒数。对于二进制消息,它是一种比 struct timespec
更容易处理的格式。本质上:
#define _POSIX_C_SOURCE 200809L
#include <stdint.h>
#include <time.h>
typedef int64_t nstime;
#define NSTIME_MIN INT64_MIN
#define NSTIME_MAX INT64_MAX
nstime nstime_realtime(void)
{
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts))
return NSTIME_MIN;
return ((nstime)ts.tv_sec * 1000000000)
+ (nstime)ts.tv_nsec;
}
double nstime_secs(const nstime ns)
{
return (double)ns / 1000000000.0;
}
struct timespec nstime_timespec(const nstime ns)
{
struct timespec ts;
if (ns < 0) {
ts.tv_sec = (time_t)(ns / -1000000000);
ts.tv_nsec = -(long)((-ns) % 1000000000);
if (ts.tv_nsec < 0L) {
ts.tv_sec--;
ts.tv_nsec += 1000000000L;
}
} else {
ts.tv_sec = (time_t)(ns / 1000000000);
ts.tv_nsec = (long)(ns % 1000000000);
}
}
您可以随意添加和减去 nstime
时间戳,它们也适用于二进制存储(尽管存在字节顺序(又名字节顺序)问题)。
(注意上面的代码是未经测试的,我认为是public domain/CC0。)
使用clock_gettime()
即可。 CLOCK_REALTIME
和 CLOCK_MONOTONIC
都是系统范围的,即如果在同一物理时刻执行,则应该在不同进程中报告完全相同的结果。
CLOCK_REALTIME
在所有 POSIXy 系统中都可用,但 CLOCK_MONOTONIC
是可选的。两者都不受夏令时变化的影响。增量 NTP 调整会影响两者。管理员对系统时间的手动更改仅影响 CLOCK_REALTIME
。 CLOCK_REALTIME
的纪元当前是 1970 年 1 月 1 日,00:00:00,但未指定 CLOCK_MONOTONIC
。
就我个人而言,我建议使用 clock_gettime(CLOCK_REALTIME,)
,因为这样您的应用程序就可以跨集群中的进程进行通信,而不仅仅是在本地计算机上;集群节点可以为 CLOCK_MONOTONIC
.
使用不同的纪元
我已经实现了两个带有两个消息队列的单线程进程 A 和 B [发送和接收的单独队列]。进程 A 将消息发送给 B,并在接收队列中等待回复。
我想从进程 A 发送一个时间戳到进程 B。如果进程 B 在 10 秒后收到消息,我想从进程 B 向 A 发送一个错误字符串。
精度应该以毫秒为单位。
在我使用的进程A中,
struct timespec msg_dispatch_time;
clock_gettime(CLOCK_REALTIME, &msg_dispatch_time);
:
:
add_timestamp_in_msg(msg, msg_dispatch_time);
:
if (msgsnd(msqid, msg, sizeof(msg), msgflg) == -1)
perror("msgop: msgsnd failed");
进程B中,
struct timespec msg_dispatch_time;
struct timespec msg_receive_time;
:
clock_gettime(CLOCK_REALTIME, &msg_received_time);
:
if( !(time_diff(msg_received_time, msg_dispatch_time) >= 10 ))
msgsnd(msqid, &sbuf, buf_length, msg_flag)
else
{
/*send the error string.*/
//msgsnd(msgid,)
}
我的问题是,
1) 如何在这里写一个 time_diff 函数以毫秒精度与 10 秒进行比较?
if( !(time_diff(msg_received_time, msg_dispatch_time) >= 10 ))
/********Existing time diff code******************/
long int time_diff (struct timeval time1, struct timeval time2)
{
struct timeval diff,
if (time1.tv_usec < time2.tv_usec) {
time1.tv_usec += 1000000;
time1.tv_sec--;
}
diff.tv_usec = time1.tv_usec - time2.tv_usec;
diff.tv_sec = time1.tv_sec - time2.tv_sec;
return diff.tv_sec; //return the diff in second
}
2) clock_gettime 是否可以在同一系统中跨进程使用?
如果您希望继续使用 struct timespec
类型,那么我建议使用 struct timespec
类型的等效 difftime()
,即
double difftimespec(const struct timespec after, const struct timespec before)
{
return (double)(after.tv_sec - before.tv_sec)
+ (double)(after.tv_nsec - before.tv_nsec) / 1000000000.0;
}
但是,我认为对于您的整体用例存在更好的选择。
如果您对程序运行到 2242 年感到满意,您可以使用 64 位带符号整数来保存自纪元以来的纳秒数。对于二进制消息,它是一种比 struct timespec
更容易处理的格式。本质上:
#define _POSIX_C_SOURCE 200809L
#include <stdint.h>
#include <time.h>
typedef int64_t nstime;
#define NSTIME_MIN INT64_MIN
#define NSTIME_MAX INT64_MAX
nstime nstime_realtime(void)
{
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts))
return NSTIME_MIN;
return ((nstime)ts.tv_sec * 1000000000)
+ (nstime)ts.tv_nsec;
}
double nstime_secs(const nstime ns)
{
return (double)ns / 1000000000.0;
}
struct timespec nstime_timespec(const nstime ns)
{
struct timespec ts;
if (ns < 0) {
ts.tv_sec = (time_t)(ns / -1000000000);
ts.tv_nsec = -(long)((-ns) % 1000000000);
if (ts.tv_nsec < 0L) {
ts.tv_sec--;
ts.tv_nsec += 1000000000L;
}
} else {
ts.tv_sec = (time_t)(ns / 1000000000);
ts.tv_nsec = (long)(ns % 1000000000);
}
}
您可以随意添加和减去 nstime
时间戳,它们也适用于二进制存储(尽管存在字节顺序(又名字节顺序)问题)。
(注意上面的代码是未经测试的,我认为是public domain/CC0。)
使用clock_gettime()
即可。 CLOCK_REALTIME
和 CLOCK_MONOTONIC
都是系统范围的,即如果在同一物理时刻执行,则应该在不同进程中报告完全相同的结果。
CLOCK_REALTIME
在所有 POSIXy 系统中都可用,但 CLOCK_MONOTONIC
是可选的。两者都不受夏令时变化的影响。增量 NTP 调整会影响两者。管理员对系统时间的手动更改仅影响 CLOCK_REALTIME
。 CLOCK_REALTIME
的纪元当前是 1970 年 1 月 1 日,00:00:00,但未指定 CLOCK_MONOTONIC
。
就我个人而言,我建议使用 clock_gettime(CLOCK_REALTIME,)
,因为这样您的应用程序就可以跨集群中的进程进行通信,而不仅仅是在本地计算机上;集群节点可以为 CLOCK_MONOTONIC
.