linux中的进程间通信应该使用哪个时钟?

Posted

技术标签:

【中文标题】linux中的进程间通信应该使用哪个时钟?【英文标题】:Which clock should be used for inter process communication in linux? 【发布时间】:2016-09-29 05:24:48 【问题描述】:

我已经实现了两个单线程进程 A 和 B,带有两个 msg 队列 [用于发送和接收的单独队列]。进程 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 是否可以在同一系统中跨进程使用?

【问题讨论】:

enum NS_PER_SECOND = 1000000000 ; void sub_timespec(struct timespec t1, struct timespec t2, struct timespec *td) td-&gt;tv_nsec = t2.tv_nsec - t1.tv_nsec; td-&gt;tv_sec = t2.tv_sec - t1.tv_sec; if (td-&gt;tv_sec &gt; 0 &amp;&amp; td-&gt;tv_nsec &lt; 0) td-&gt;tv_nsec += NS_PER_SECOND; td-&gt;tv_sec--; else if (td-&gt;tv_sec &lt; 0 &amp;&amp; td-&gt;tv_nsec &gt; 0) td-&gt;tv_nsec -= NS_PER_SECOND; td-&gt;tv_sec++; 在gnu.org/software/libc/manual/html_node/Elapsed-Time.html中检查timeval_subtract @NulledPointer: timeval_subtract() 是为struct timeval 而不是struct timespec,不是吗?但这些概念当然可以应用于其他类型。 【参考方案1】:

如果您希望继续使用 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 位有符号整数来保存自 Epoch 以来的纳秒数。对于二进制消息,它比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_REALTIMECLOCK_REALTIME 的纪元当前是 1970 年 1 月 1 日 00:00:00,但未指定 CLOCK_MONOTONIC

就我个人而言,我推荐使用clock_gettime(CLOCK_REALTIME,),因为这样您的应用程序就可以跨集群中的进程进行通信,而不仅仅是在本地机器上;集群节点可以为CLOCK_MONOTONIC 使用不同的纪元。

【讨论】:

以上是关于linux中的进程间通信应该使用哪个时钟?的主要内容,如果未能解决你的问题,请参考以下文章

Linux进程间通信总结

Linux进程间通信总结

Linux进程间通信总结

Linux进程间通信总结

Java Attach API 使用啥进程间通信机制?

进程间通信