在Linux中进行进程间通信应该使用哪个时钟?

3

我已经实现了两个单线程进程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在同一系统中的进程间使用是否安全?


1
enum { NS_PER_SECOND = 1000000000 }; void sub_timespec(struct timespec t1, struct timespec t2, struct timespec *td) { td->tv_nsec = t2.tv_nsec - t1.tv_nsec; td->tv_sec = t2.tv_sec - t1.tv_sec; if (td->tv_sec > 0 && td->tv_nsec < 0) { td->tv_nsec += NS_PER_SECOND; td->tv_sec--; } else if (td->tv_sec < 0 && td->tv_nsec > 0) { td->tv_nsec -= NS_PER_SECOND; td->tv_sec++; } } - Jonathan Leffler
1
请查看http://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html中的`timeval_subtract`。 - JamesWebbTelescopeAlien
1
@NulledPointer: timeval_subtract() 是针对 struct timeval 而不是 struct timespec,是吗?但是这些概念可以应用于其他类型。 - Jonathan Leffler
1个回答

2
如果您希望继续使用struct timespec类型,则建议使用difftime()等效方法来处理struct timespec类型,即:
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 时间戳,并且它们也适合于二进制存储(字节顺序问题除外)。
(请注意,上面的代码未经测试,我认为它是公共领域/CC0。)
使用 clock_gettime() 是可以的。 CLOCK_REALTIMECLOCK_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 使用不同的纪元。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接