Last active
May 26, 2025 04:49
-
-
Save colrichie/019fa2b75b9842d2c06cbfc51f4115e6 to your computer and use it in GitHub Desktop.
Various Implementations of the "waitll" method and the Punctual Class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
##################################################################### | |
# | |
# A Sample Program of waitill for AWK (except mawk) | |
# | |
# You can make a more accurate loop by using the "waitill" function (*1) | |
# than by using the 'system("sleep n")' function simply. | |
# | |
# The following AWK script prints a message every 0.5 ms accurately. | |
# | |
# THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
# | |
# (*1) To run this script, you must install the "Tokideli" command set | |
# in advance. "Tokideli" is published on the following website. | |
# https://github.com/ShellShoccar-jpn/tokideli | |
# | |
# Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
# | |
##################################################################### | |
exit_trap() { | |
set -- ${1:-} $? # $? is set as $1 if no argument given | |
trap '' EXIT HUP INT QUIT PIPE ALRM TERM | |
[ -d "${Tmp:-}" ] && rm -rf "${Tmp%/*}/_${Tmp##*/_}" | |
trap - EXIT HUP INT QUIT PIPE ALRM TERM | |
exit $1 | |
} | |
error_exit() { ${2+:} false && echo "${0##*/}: $2" 1>&2; exit $1; } | |
case "$(awk -W interactive 'BEGIN{exit;}' 2>&1)" in | |
'') error_exit 1 'Your AWK implementation is mawk, and not supported :-(';; | |
esac | |
trap 'exit_trap' EXIT HUP INT QUIT PIPE ALRM TERM | |
Tmp=`mktemp -d -t "_${0##*/}.$$.XXXXXXXXXXX"` || error_exit 1 'Failed to mktemp' | |
mkfifo "$Tmp/tscat" || error_exit 1 'Failed to mkfifo (tscat)' | |
mkfifo "$Tmp/linets" || error_exit 1 'Failed to mkfifo (linets)' | |
awk -v __PUNCTUAL_FIFO_t="$Tmp/tscat" -v __PUNCTUAL_FIFO_l="$Tmp/linets" ' | |
function new_punctual(mode, __dummy) { | |
__PUNCTUAL_CMD_t = "tscat -1z " __PUNCTUAL_FIFO_t; | |
__PUNCTUAL_CMD_t | getline __dummy; | |
mode = (mode!="") ? mode : "9e"; | |
__PUNCTUAL_CMD_l = "linets -1" mode " " __PUNCTUAL_FIFO_l; | |
__PUNCTUAL_CMD_l | getline __dummy; | |
print 1 > __PUNCTUAL_FIFO_l; fflush(); | |
__PUNCTUAL_CMD_l | getline WT_EPOCH; | |
} | |
function now(__dummy) { | |
print 1 > __PUNCTUAL_FIFO_l; fflush(); | |
__PUNCTUAL_CMD_l | getline __dummy; | |
return substr(dummy,1,index(__dummy," ")-1); | |
} | |
function get_epoch() { return WT_EPOCH; } | |
function reset_epoch(__dummy) { | |
print -1 > __PUNCTUAL_FIFO_t; fflush(); | |
__PUNCTUAL_CMD_t | getline __dummy; | |
print 1 > __PUNCTUAL_FIFO_l; fflush(); | |
__PUNCTUAL_CMD_l | getline WT_EPOCH; | |
return WT_EPOCH; | |
} | |
function waitill(sec_to_ret, __dummy) { | |
print sec_to_ret > __PUNCTUAL_FIFO_t; fflush(); | |
__PUNCTUAL_CMD_t | getline __dummy; | |
} | |
function delete_punctual() { | |
close(__PUNCTUAL_FIFO_t); close(__PUNCTUAL_CMD_t ); | |
close(__PUNCTUAL_FIFO_l); close(__PUNCTUAL_CMD_l ); | |
} | |
BEGIN { | |
new_punctual(); | |
print "Set the epoch."; | |
for (t=0.5; t<=5.0; t+=0.5) { | |
waitill(t); | |
printf("%.1f second(s) have passed.\n",t); | |
} | |
delete_punctual(); | |
} | |
' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
////////////////////////////////////////////////////////////////////// | |
// | |
// A Sample Program of waitill() for C11 with POSIX | |
// | |
// You can make an accurate interval loop a little simpler by using the | |
// "waitill()" function than by using the "clock_nanosleep()" function. | |
// | |
// The following C11 program prints a message every 0.5 ms accurately. | |
// | |
// THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
// | |
// Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
// | |
////////////////////////////////////////////////////////////////////// | |
#include <errno.h> | |
#include <math.h> | |
#include <stdio.h> | |
#include <time.h> | |
struct timespec wt_epoch; | |
int new_punctual(void) { | |
return clock_gettime(CLOCK_REALTIME,&wt_epoch); | |
} | |
int now(struct timespec* pts) { | |
if (pts==NULL) {errno=EINVAL; return -1;} | |
return clock_gettime(CLOCK_REALTIME,pts); | |
} | |
int reset_epoch() { | |
return clock_gettime(CLOCK_REALTIME,&wt_epoch); | |
} | |
int waitill_d(double sec_to_ret) { | |
struct timespec due={0}; | |
double i,d; | |
d=modf(sec_to_ret,&i); | |
due.tv_nsec=wt_epoch.tv_nsec+(long)(d*1000000000L); | |
if (due.tv_nsec>999999999L) {due.tv_nsec-=1000000000L;due.tv_sec++;} | |
due.tv_sec+=wt_epoch.tv_sec+(time_t)i; | |
if (due.tv_sec<wt_epoch.tv_sec) { | |
due.tv_sec =(time_t)((~(time_t)0)>>1); | |
due.tv_nsec=999999999L; | |
} | |
return clock_nanosleep(CLOCK_REALTIME,TIMER_ABSTIME,&due,NULL); | |
} | |
int waitill_ts(struct timespec *duration) { | |
int i; | |
struct timespec due={0}; | |
if (duration==NULL) {errno=EINVAL; return -1;} | |
due.tv_sec =wt_epoch.tv_sec +duration->tv_sec; | |
due.tv_nsec=wt_epoch.tv_nsec+duration->tv_nsec; | |
if (due.tv_nsec>999999999L) {due.tv_nsec-=1000000000L;due.tv_sec++;} | |
if (due.tv_sec<wt_epoch.tv_sec) { | |
due.tv_sec =(time_t)((~(time_t)0)>>1); | |
due.tv_nsec=999999999L; | |
} | |
return clock_nanosleep(CLOCK_REALTIME,TIMER_ABSTIME,&due,NULL); | |
} | |
#define waitill(duration) _Generic((duration), \ | |
double : waitill_d, \ | |
struct timespec* : waitill_ts \ | |
)(duration) | |
int main(void) { | |
int i; | |
if ((i=new_punctual())!=0) {return i;} | |
printf("Set the epoch.\n"); | |
for (double t=0.5; t<=5.0; t+=0.5) { | |
if ((i=waitill(t))!=0) {return i;} | |
printf("%.1f second(s) have passed.\n", t); | |
} | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
////////////////////////////////////////////////////////////////////// | |
// | |
// A Sample Program of waitill() for C++17 | |
// | |
// You can make an accurate interval loop a little simpler by using the | |
// "Punctual::waitill()" method than by using the | |
// "std::this_thread::sleep_until()" function. | |
// | |
// The following C++ program prints a message every 0.5 ms accurately. | |
// | |
// THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
// | |
// Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
// | |
////////////////////////////////////////////////////////////////////// | |
#include <chrono> // for std::chrono | |
#include <ctime> // for std::timespec | |
#include <thread> // for std::this_thread::sleep_until | |
#include <iostream> | |
class Punctual { | |
private: | |
using hr_clk = std::chrono::high_resolution_clock; | |
using time_point = hr_clk::time_point; | |
using duration = hr_clk::duration; | |
time_point wt_epoch; | |
public: | |
Punctual() {wt_epoch = hr_clk::now();} | |
time_point now() const {return hr_clk::now(); } | |
time_point get_epoch() const {return wt_epoch; } | |
time_point reset_epoch() {wt_epoch = hr_clk::now(); | |
return wt_epoch; } | |
bool waitill(double sec_to_ret) { | |
using namespace std::chrono; | |
auto duration = std::chrono::duration<double>(sec_to_ret); | |
auto due = wt_epoch + duration_cast<hr_clk::duration>(duration); | |
std::this_thread::sleep_until(due); | |
return true; | |
} | |
bool waitill(duration duration_to_ret) { | |
auto due = wt_epoch + duration_to_ret; | |
std::this_thread::sleep_until(due); | |
return true; | |
} | |
bool waitill(std::timespec& ts) { | |
auto due = wt_epoch + std::chrono::seconds( ts.tv_sec ) | |
+ std::chrono::nanoseconds(ts.tv_nsec); | |
std::this_thread::sleep_until(due); | |
return true; | |
} | |
}; | |
int main() { | |
Punctual punc; | |
std::cout << "Set the epoch.\n"; | |
for (double t=0.5; t<=5.0; t+=0.5) { | |
punc.waitill(t); | |
std::cout << t << " second(s) have passed." << std::endl; | |
} | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
////////////////////////////////////////////////////////////////////// | |
// | |
// A Sample Program of waitill() for C# | |
// | |
// You can make a more accurate interval loop by using the | |
// "Punctual.Waitill()" method than by using both the "Thread.Sleep()" | |
// and "Task.Delay()" methods simply. | |
// | |
// The following C# program prints a message every 0.5 ms accurately. | |
// | |
// THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
// | |
// Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
// | |
////////////////////////////////////////////////////////////////////// | |
using System; | |
using System.Threading.Tasks; | |
public class Punctual { | |
private DateTime wtEpoch; | |
public Punctual() {wtEpoch = DateTime.Now;} | |
public DateTime Now() {return DateTime.Now; } | |
public DateTime GetEpoch() {return wtEpoch; } | |
public DateTime ResetEpoch() {wtEpoch = DateTime.Now; | |
return wtEpoch; } | |
public async Task<bool> Waitill(double secToRet) { | |
var due = wtEpoch.AddSeconds(secToRet); | |
var now = DateTime.Now; | |
var duration = due - now; | |
if (duration.TotalMilliseconds > 0) { | |
await Task.Delay(duration); | |
} | |
return true; | |
} | |
} | |
public class Example { | |
public static async Task Main() { | |
var punctual = new Punctual(); | |
Console.WriteLine("Set the epoch."); | |
double t = 0.5; | |
double step = 0.5; | |
double max = 5.0; | |
while (t <= max) { | |
await punctual.Waitill(t); | |
Console.WriteLine($"{t:F1} second(s) have passed."); | |
t += step; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% | |
% A Sample Program of waitill() for Erlang | |
% | |
% You can make a more accurate interval loop by using the waitill() | |
% function of the Punctual module than by using the "timer:sleep()" | |
% function simply. | |
% | |
% The following Erlang program prints a message every 0.5 ms accurately. | |
% | |
% THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
% | |
% Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
% | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
-module(punctual). | |
-export([start/0, example/0]). | |
%%%------------------------- | |
%%% Punctual module | |
%%%------------------------- | |
start() -> | |
spawn(fun() -> loop(os:system_time(nanosecond)) end). | |
loop(WtEpoch) -> | |
receive | |
{From, now} -> | |
NowNano = os:system_time(nanosecond), | |
From ! {self(), NowNano / 1_000_000_000}, | |
loop(WtEpoch); | |
{From, get_epoch} -> | |
From ! {self(), WtEpoch / 1_000_000_000}, | |
loop(WtEpoch); | |
{From, reset_epoch} -> | |
NewEpoch = os:system_time(nanosecond), | |
From ! {self(), NewEpoch / 1_000_000_000}, | |
loop(NewEpoch); | |
{From, {waitill, SecToRet}} -> | |
Due = WtEpoch + trunc(SecToRet * 1_000_000_000), | |
Now = os:system_time(nanosecond), | |
Nsec = Due - Now, | |
( if | |
Nsec > 0 -> | |
timer:sleep(Nsec div 1_000_000); | |
true -> | |
ok | |
end ), | |
From ! {self(), true}, | |
loop(WtEpoch) | |
end. | |
%%%------------------------- | |
%%% Usage | |
%%%------------------------- | |
example() -> | |
Pid = start(), | |
io:put_chars("Set the epoch.\n"), | |
loop(Pid, 0.5, 0.5, 5.0). | |
loop(_Pid, T, _Step, Max) when T > Max -> | |
ok; | |
loop(Pid, T, Step, Max) -> | |
Pid ! {self(), {waitill, T}}, | |
receive | |
{Pid, true} -> | |
io:format("~.1f second(s) have passed.~n", [T]), | |
loop(Pid, T + Step, Step, Max) | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
##################################################################### | |
# | |
# A Sample Program of waitill() for Elixer | |
# | |
# You can make a more accurate interval loop by using the waitill() | |
# function of the Punctual module than by using the "timer:sleep()" | |
# function simply. | |
# | |
# The following Elixer program prints a message every 0.5 ms accurately. | |
# | |
# THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
# | |
# Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
# | |
##################################################################### | |
#------------------------- | |
# Punctual module | |
#------------------------- | |
defmodule Punctual do | |
def start do | |
spawn(fn -> loop(System.os_time(:nanosecond)) end) | |
end | |
defp loop(wt_epoch) do | |
receive do | |
{:now, from} -> | |
now = System.os_time(:nanosecond) | |
send(from, {:ok, now / 1_000_000_000}) | |
loop(wt_epoch) | |
{:get_epoch, from} -> | |
send(from, {:ok, wt_epoch / 1_000_000_000}) | |
loop(wt_epoch) | |
{:reset_epoch, from} -> | |
new_epoch = System.os_time(:nanosecond) | |
send(from, {:ok, new_epoch / 1_000_000_000}) | |
loop(new_epoch) | |
{{:waitill, sec_to_ret}, from} -> | |
due = wt_epoch + trunc(sec_to_ret * 1_000_000_000) | |
now = System.os_time(:nanosecond) | |
nsec = due - now | |
if nsec > 0 do | |
:timer.sleep(div(nsec, 1_000_000)) | |
end | |
send(from, {:ok, true}) | |
loop(wt_epoch) | |
end | |
end | |
end | |
#------------------------- | |
# Usage | |
#------------------------- | |
defmodule Example do | |
def run do | |
pid = Punctual.start() | |
IO.puts("Set the epoch.") | |
loop(pid, 0.5, 0.5, 5.0) | |
end | |
defp loop(_pid, t, _step, max) when t > max, do: :ok | |
defp loop(pid, t, step, max) do | |
send(pid, {{:waitill, t}, self()}) | |
receive do | |
{:ok, true} -> | |
IO.puts("#{Float.round(t, 1)} second(s) have passed.") | |
loop(pid, t + step, step, max) | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
////////////////////////////////////////////////////////////////////// | |
// | |
// A Sample Program of waitill() for Golang | |
// | |
// You can make a more accurate interval loop by using the "Punctual.Waitill()" | |
// method than by using the "time.Sleep()" function simply. | |
// | |
// The following Golang program can make the 0.5 ms interval printing | |
// more accurate than typical sample programs. | |
// | |
// THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
// | |
// Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
// | |
////////////////////////////////////////////////////////////////////// | |
package main | |
import ( | |
"fmt" | |
"time" | |
) | |
type Punctual struct {wt_epoch time.Time} | |
func NewPunctual() *Punctual {return &Punctual{ | |
wt_epoch: time.Now()}} | |
func (p *Punctual) Now() time.Time {return time.Now() } | |
func (p *Punctual) ResetEpoch() time.Time {p.wt_epoch=time.Now() | |
return p.wt_epoch } | |
func (p *Punctual) GetEpoch() time.Time {return p.wt_epoch } | |
func (p *Punctual) Waitill(secToRet float64) bool { | |
due := p.wt_epoch.Add(time.Duration(secToRet * float64(time.Second))) | |
now := time.Now() | |
if due.After(now) { | |
duration := due.Sub(now) | |
time.Sleep(duration) | |
} | |
return true | |
} | |
func main() { | |
p := NewPunctual() | |
fmt.Println("Set the epoch.") | |
for t := 0.5; t <= 5.0; t += 0.5 { | |
p.Waitill(t) | |
fmt.Printf("%.1f second(s) have passed.\n", t) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
---------------------------------------------------------------------- | |
-- | |
-- A Sample Program of waitill() for Haskell | |
-- | |
-- You can make a more accurate interval loop by using the "waitill()" | |
-- function than by using the "threadDelay()" function simply. | |
-- | |
-- The following Haskell program can make the 0.5 ms interval printing | |
-- more accurate than typical sample programs. | |
-- | |
-- THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
-- | |
-- Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
-- | |
---------------------------------------------------------------------- | |
import Data.IORef | |
import Control.Concurrent (threadDelay) | |
import System.Clock | |
-- The "Punctual" type class | |
data Punctual = Punctual { wtEpoch :: TimeSpec } | |
new :: IO Punctual | |
new = do | |
t <- getTime Realtime | |
return $ Punctual { wtEpoch = t } | |
now :: IO Double | |
now = do | |
TimeSpec s n <- getTime Realtime | |
return $ fromIntegral s + fromIntegral n / 1e9 | |
getEpoch :: Punctual -> IO Double | |
getEpoch (Punctual t) = do | |
let TimeSpec s n = t | |
return $ fromIntegral s + fromIntegral n / 1e9 | |
resetEpoch :: IORef TimeSpec -> IO Double | |
resetEpoch ref = do | |
t@(TimeSpec s n) <- getTime Realtime | |
writeIORef ref t | |
return $ fromIntegral s + fromIntegral n / 1e9 | |
waitill :: Punctual -> Double -> IO () | |
waitill (Punctual secToRet) due = do | |
now <- getTime Realtime | |
let elapsed = fromIntegral (toNanoSecs (now - secToRet)) / 1e9 | |
duration = due - elapsed | |
if duration > 0 | |
then threadDelay (floor $ duration * 1e6) | |
else return () | |
-- Example | |
main :: IO () | |
main = do | |
punctual <- new | |
putStrLn "Set the epoch." | |
let loop t | |
| t > 5.0 = return () | |
| otherwise = do | |
waitill punctual t | |
putStrLn $ show t ++ " second(s) have passed." | |
loop (t + 0.5) | |
loop 0.5 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
////////////////////////////////////////////////////////////////////// | |
// | |
// A Sample Program of waitill() for Java | |
// | |
// You can make a more accurate interval loop by using the "Punctual.waitill()" | |
// method than by using the "Thread.sleep()" function simply. | |
// | |
// The following Java program prints a message every 0.5 ms accurately. | |
// | |
// THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
// | |
// Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
// | |
////////////////////////////////////////////////////////////////////// | |
import java.time.Instant; | |
import java.time.Duration; | |
public class Punctual { | |
private Instant wtEpoch; | |
public Punctual() {this.wtEpoch = Instant.now();} | |
public Instant now() {return Instant.now();} | |
public Instant getEpoch() {return wtEpoch;} | |
public Instant resetEpoch() {this.wtEpoch = Instant.now(); | |
return this.wtEpoch; } | |
public boolean waitill(double secToRet) { | |
Instant due = wtEpoch.plusNanos((long)(secToRet * 1_000_000_000)); | |
Duration duration = Duration.between(Instant.now(), due); | |
if (!duration.isNegative()) { | |
try { | |
Thread.sleep(duration.toMillis(), duration.getNano() % 1_000_000); | |
return true; | |
} catch (InterruptedException e) { | |
Thread.currentThread().interrupt(); | |
return false; | |
} | |
} | |
return true; | |
} | |
} | |
/* If you try the Punctual.waitill(), make a file as "Main.java" and write | |
the following code. Then, compile them and run the Main.main() function. | |
``` | |
public class Main { | |
public static void main(String[] args) { | |
Punctual punc = new Punctual(); | |
System.out.println("Set the epoch."); | |
for (double t = 0.5; t <= 5.0; t += 0.5) { | |
punc.waitill(t); | |
System.out.printf("%.1f second(s) have passed.\n", t); | |
} | |
} | |
} | |
``` | |
According to the Java language specification, it is impossible to show | |
you a sample program containing both the public Punctual class and the | |
Main class in one file. :( | |
*/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
////////////////////////////////////////////////////////////////////// | |
// | |
// A Sample Program of waitill() for JavaScript | |
// | |
// You can make a more accurate interval loop by using the | |
// "Punctual.prototype.waitill()" method than by using the setTimeout() | |
// function simply. | |
// | |
// The following JavaScript program can make the 0.5 ms interval printing | |
// more accurate than typical sample programs. | |
// | |
// THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
// | |
// Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
// | |
////////////////////////////////////////////////////////////////////// | |
class Punctual { | |
#wt_epoch; | |
constructor() {this.#wt_epoch = new Date(); } | |
now() {return new Date(); } | |
get_epoch() {return new Date(this.#wt_epoch.getTime());} | |
reset_epoch() {this.#wt_epoch = new Date(); | |
return new Date(this.#wt_epoch.getTime());} | |
async waitill(sec_since_epoch) { | |
if (typeof(sec_since_epoch)!=='number' || isNaN(sec_since_epoch)) { | |
throw new Error('"sec_since_epoch" argument must be a valid number'); | |
} | |
const dt = new Date() - this.#wt_epoch; | |
const msec = sec_since_epoch*1000 - dt; | |
if (msec <= 0 ) {return;} | |
await new Promise(res => setTimeout(res,msec)); | |
return true; | |
} | |
} | |
(async () => { | |
const punc = new Punctual(); | |
console.log('Set the epoch.'); | |
for (let t=0.5; t<=5.0; t+=0.5) { | |
await punc.waitill(t); | |
console.log(t+' second(s) have passed.'); | |
} | |
})(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
exec php -q "$0" "$@" | |
<?php | |
###################################################################### | |
# | |
# A Sample Program of waitill() for PHP | |
# | |
# You can make an accurate interval loop a little simpler by using the | |
# "Punctual::waitill()" method than by using the time_sleep_until(). | |
# | |
# The following PHP script prints a message every 0.5 ms accurately. | |
# | |
# THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
# | |
# Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
# | |
###################################################################### | |
class Punctual { | |
private float $wt_epoch; | |
public function __construct() { | |
$this->wt_epoch = microtime(true); | |
} | |
public function now(): float { | |
return microtime(true); | |
} | |
public function get_epoch(): float { | |
return $this->wt_epoch; | |
} | |
public function reset_epoch(): float { | |
$this->wt_epoch = microtime(true); | |
return $this->wt_epoch; | |
} | |
public function waitill(float $sec_to_ret): bool { | |
$time_to_ret = $this->wt_epoch + $sec_to_ret; | |
$old_err_lv = error_reporting(E_ERROR | E_PARSE); | |
time_sleep_until($time_to_ret); | |
error_reporting($old_err_lv); | |
return true; | |
} | |
} | |
$punc = new Punctual(); | |
echo "Set the epoch.\n"; | |
for ($t=0.5; $t<=5.0; $t+=0.5) { | |
$punc->waitill($t); | |
printf("%.1f second(s) have passed.\n", $t); | |
} | |
?> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
###################################################################### | |
# | |
# A Sample Program of waitill() for Perl | |
# | |
# You can make a more accurate interval loop by using the "Punctual::waitill()" | |
# function than by using the Time::HiRes::sleep() function simply. | |
# | |
# The following Perl script can make the 0.5 ms interval printing | |
# more accurate than typical sample programs. | |
# | |
# THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
# | |
# Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
# | |
###################################################################### | |
use strict; | |
use warnings; | |
package Punctual; | |
use Time::HiRes qw(time sleep); | |
sub new {my $class = shift; | |
my $self = {_wt_epoch => Time::HiRes::time()}; | |
bless $self, $class; | |
return $self; } | |
sub now {return Time::HiRes::time(); } | |
sub get_epoch {my $self = shift; return $self->{_wt_epoch}; } | |
sub reset_epoch {my $self = shift; | |
$self->{_wt_epoch} = Time::HiRes::time(); | |
return $self->{_wt_epoch}; } | |
sub waitill {my ($self, $sec_to_ret) = @_; | |
my $due = $self->{_wt_epoch}+$sec_to_ret; | |
my $now = Time::HiRes::time(); | |
my $sec = $due-$now; | |
if ($sec > 0) {Time::HiRes::sleep($sec);} | |
return 1; } | |
1; | |
package main; | |
my $punc = Punctual->new(); | |
print "Set the epoch.\n"; | |
for (my $t=0.5; $t<=5.0; $t+=0.5) { | |
$punc->waitill($t); | |
printf("%.1f second(s) have passed.\n",$t); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# #################################################################### | |
# | |
# A Sample Program of waitill() for Python3 | |
# | |
# You can make a more accurate interval loop by using the "Punctual.waitill()" | |
# function than by using the time.sleep() function simply. | |
# | |
# The following Python script can make the 0.5 ms interval printing | |
# more accurate than typical sample programs. | |
# | |
# THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
# | |
# Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
# | |
# #################################################################### | |
import datetime | |
import time | |
class Punctual: | |
_wt_epoch = 0 | |
def __init__(self): | |
self._wt_epoch = datetime.datetime.now() | |
return | |
def now(self): | |
return datetime.datetime.now() | |
def get_epoch(self): | |
return self._wt_epoch.replace(minute=0) | |
def reset_epoch(self): | |
self._wt_epoch = datetime.datetime.now() | |
return self._wt_epoch.replace(minute=0) | |
def waitill(self, sec_since_epoch): | |
try: | |
if not isinstance(sec_since_epoch, (int, float)): | |
raise TypeError(f'"sec_since_epoch" must be int or float') | |
dt = datetime.datetime.now() - self._wt_epoch | |
sec = sec_since_epoch - dt.total_seconds() | |
if sec > 0: | |
time.sleep(sec) | |
return True | |
except (ValueError, TypeError): | |
return False | |
punc = Punctual() | |
print("Set the epoch.") | |
for i in range(10): | |
t = (i+1) * 0.5 | |
punc.waitill(t) | |
print("{:03.1f} second(s) have passed.".format(t)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
###################################################################### | |
# | |
# A Sample Program of waitill() for Ruby | |
# | |
# You can make a more accurate interval loop by using the "Punctual.waitill()" | |
# function than by using the time.sleep() function simply. | |
# | |
# The following Ruby script can make the 0.5 ms interval printing | |
# more accurate than typical sample programs. | |
# | |
# THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
# | |
# Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
# | |
###################################################################### | |
class Punctual | |
def initialize | |
@wt_epoch = Time.now | |
end | |
def now | |
Time.now | |
end | |
def get_epoch | |
@wt_epoch.dup | |
end | |
def reset_epoch | |
@wt_epoch = Time.now | |
@wt_epoch.dup | |
end | |
def waitill(sec_to_ret) | |
dt = Time.now - @wt_epoch | |
sec = sec_to_ret - dt | |
sleep(sec) if sec > 0 | |
true | |
end | |
end | |
punc = Punctual.new | |
puts "Set the epoch." | |
0.5.step(5.0, 0.5) do |t| | |
punc.waitill(t) | |
printf("%.1f second(s) have passed.\n",t) | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
////////////////////////////////////////////////////////////////////// | |
// | |
// A Sample Program of waitill() for Rust | |
// | |
// You can make a little simpler interval loop by using the | |
// "Punctual::waitill()" method than by using the | |
// "std::thread::sleep::sleep()" function simply. | |
// | |
// The following Rust program prints a message every 0.5 ms accurately. | |
// | |
// THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
// | |
// Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
// | |
////////////////////////////////////////////////////////////////////// | |
use std::time::{Duration, Instant}; | |
use std::thread::sleep; | |
struct Punctual {wt_epoch: Instant} | |
impl Punctual { | |
fn new() -> Self {Punctual {wt_epoch: Instant::now()}} | |
fn now(&self) -> Instant {Instant::now() } | |
fn get_epoch(&self) -> Instant {self.wt_epoch } | |
fn reset_epoch(&mut self) -> Instant {self.wt_epoch=Instant::now(); | |
self.wt_epoch } | |
fn waitill(&self, sec_to_ret: f64) -> bool { | |
let due = self.wt_epoch + Duration::from_secs_f64(sec_to_ret); | |
let now = Instant::now(); | |
if due > now {sleep(due - now)} | |
true | |
} | |
} | |
fn main() { | |
let mut punc = Punctual::new(); | |
println!("Set the epoch."); | |
let mut t = 0.5; | |
while t <= 5.0 { | |
punc.waitill(t); | |
println!("{:.1} second(s) have passed.", t); | |
t += 0.5; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
##################################################################### | |
# | |
# A Sample Program of waitill for shell script #1 | |
# | |
# You can make a more accurate loop by using the "waitill" command (*1) | |
# than by using the sleep command simply. | |
# | |
# The following shell script prints a message every 0.5 ms accurately. | |
# | |
# THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
# | |
# (*1) To run this script, you must install the "Tokideli" command set | |
# in advance. "Tokideli" is published on the following website. | |
# https://github.com/ShellShoccar-jpn/tokideli | |
# | |
# Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
# | |
##################################################################### | |
now() { [ $# -eq 0 ] && set -- 9e; herewego -$1 0; } | |
get_epoch() { echo $WT_EPOCH; } | |
reset_epoch() { export WT_EPOCH=+$(now); echo $WT_EPOCH; } | |
new_punctual() { export WT_EPOCH=+$(now); } | |
new_punctual | |
echo 'Set the epoch.' | |
for t in 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0; do | |
waitill -e $t | |
echo "$t second(s) have passed." | |
done |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' | |
' | |
' A Sample Program of waitill() for VB.NET | |
' | |
' You can make a more accurate interval loop by using the | |
' "Punctual.Waitill()" method than by using the "Thread.Sleep()" | |
' method simply. | |
' | |
' The following VB.NET program prints a message every 0.5 ms accurately. | |
' | |
' THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
' | |
' Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
' | |
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' | |
Imports System | |
Imports System.Threading | |
Public Class Punctual | |
Private wtEpoch As DateTime | |
Public Sub New() | |
wtEpoch = DateTime.Now | |
End Sub | |
Public Function Now() As DateTime | |
Return DateTime.Now | |
End Function | |
Public Function GetEpoch() As DateTime | |
Return wtEpoch | |
End Function | |
Public Function ResetEpoch() As DateTime | |
wtEpoch = DateTime.Now | |
Return wtEpoch | |
End Function | |
Public Function Waitill(secToRet As Double) As Boolean | |
Dim due As DateTime = wtEpoch.AddSeconds(secToRet) | |
Dim now As DateTime = DateTime.Now | |
Dim duration As TimeSpan = due - now | |
If duration.TotalMilliseconds > 0 Then | |
Thread.Sleep(duration) | |
End If | |
Return True | |
End Function | |
End Class | |
Module Example | |
Sub Main() | |
Dim punc As New Punctual() | |
Console.WriteLine("Set the epoch.") | |
For t As Double = 0.5 To 5.0 Step 0.5 | |
punc.Waitill(t) | |
Console.WriteLine("{0:F1} second(s) have passed.", t) | |
Next | |
End Sub | |
End Module |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' | |
' | |
' A Sample Program of waitill() for VBA | |
' | |
' You can make an accurate interval loop a little simpler by using the | |
' "Waitill()" function than by using the"Application.Wait()" function. | |
' | |
' The following VBA program prints a message every 1 s accurately. | |
' | |
' THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
' | |
' Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
' | |
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' | |
Dim wtEpoch As Date | |
Sub NewPunctual() | |
wtEpoch = Now | |
End Sub | |
Function GetEpoch() As Date | |
GetEpoch = wtEpoch | |
End Function | |
Function ResetEpoch() As Date | |
wtEpoch = Now | |
ResetEpoch = wtEpoch | |
End Function | |
Function Waitill(ByVal secToRet As Double) As Boolean | |
Dim targetTime As Date | |
due = wtEpoch + TimeSerial(0, 0, secToRet) | |
If Now < due Then | |
Application.Wait due | |
End If | |
Waitill = True | |
End Function | |
Sub ExampleUsage() | |
Call NewPunctual | |
Debug.Print "Set the epoch." | |
Dim t As Integer | |
For t = 1 To 5 Step 1 | |
Call Waitill(t) | |
Debug.Print Format(t, "0") & " second(s) have passed." | |
Next t | |
End Sub |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
##################################################################### | |
# | |
# A Sample Program of waitill for shell script #2 | |
# (#2 is better than #1 if you want to make a shorter interval loop | |
# than about 0.1 second) | |
# | |
# You can make a more accurate loop by using the "waitill" command (*1) | |
# than by using the sleep command simply. | |
# | |
# The following shell script prints a message every 0.5 ms accurately. | |
# | |
# THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
# | |
# (*1) To run this script, you must install the "Tokideli" command set | |
# in advance. "Tokideli" is published on the following website. | |
# https://github.com/ShellShoccar-jpn/tokideli | |
# | |
# Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
# | |
##################################################################### | |
exit_trap() { | |
set -- ${1:-} $? # $? is set as $1 if no argument given | |
trap '' EXIT HUP INT QUIT PIPE ALRM TERM | |
[ -d "${Tmp:-}" ] && rm -rf "${Tmp%/*}/_${Tmp##*/_}" | |
trap - EXIT HUP INT QUIT PIPE ALRM TERM | |
[ -n "${PID_linets:-}" ] && kill $PID_linets | |
[ -n "${PID_tscat:-}" ] && kill $PID_tscat | |
exit $1 | |
} | |
error_exit() { ${2+:} false && echo "${0##*/}: $2" 1>&2; exit $1; } | |
trap 'exit_trap' EXIT HUP INT QUIT PIPE ALRM TERM | |
Tmp=`mktemp -d -t "_${0##*/}.$$.XXXXXXXXXXX"` || error_exit 1 'Failed to mktemp' | |
mkfifo "$Tmp/tscat2sh" || error_exit 1 'Failed to mkfifo (cmd2sh)' | |
mkfifo "$Tmp/sh2tscat" || error_exit 1 'Failed to mkfifo (sh2cmd)' | |
mkfifo "$Tmp/linets2sh" || error_exit 1 'Failed to mkfifo (cmd2sh)' | |
mkfifo "$Tmp/sh2linets" || error_exit 1 'Failed to mkfifo (sh2cmd)' | |
new_punctual() { | |
[ $# -eq 0 ] && set -- 9e | |
_punctual_mode=$1 | |
read _punctual_tmp < "$Tmp/tscat2sh" & | |
tscat -1z "$Tmp/sh2tscat" > "$Tmp/tscat2sh" & | |
PID_tscat=$! | |
export WT_EPOCH=$(herewego -$1 0) | |
exec 3>"$Tmp/sh2tscat" | |
read _punctual_tmp < "$Tmp/linets2sh" & | |
linets -1$1 "$Tmp/sh2linets" > "$Tmp/linets2sh" & | |
PID_linets=$! | |
exec 4>"$Tmp/sh2linets" | |
} | |
now() { | |
echo 1>&4 | |
read _punctual_tmp <"$Tmp/linets2sh" | |
echo "$_punctual_tmp" | |
} | |
get_epoch() { | |
echo $WT_EPOCH; | |
} | |
reset_epoch() { | |
echo -1 1>&3 | |
read _punctual_tmp <"$Tmp/tscat2sh" | |
export WT_EPOCH=$(herewego -$_punctual_mode 0) | |
} | |
waitill() { | |
[ $# -eq 0 ] && return 0 | |
echo $1 1>&3 | |
read _punctual_tmp <"$Tmp/tscat2sh" | |
} | |
new_punctual 3I | |
echo 'Set the epoch.' | |
for t in 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0; do | |
waitill $t | |
echo "$t second(s) have passed." | |
sleep 0.1 | |
done |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
////////////////////////////////////////////////////////////////////// | |
// | |
// A Sample Program of waitill() for Arduino | |
// | |
// You can make a more accurate loop by using the "waitill()" function | |
// than by using the delay() function simply. | |
// | |
// The following Arduino sketch can make the 0.5 ms LED blinking more | |
// accurate than typical sample programs. | |
// | |
// THIS SAMPLE IS DEDICATED TO PUNCTUAL PROGRAMMERS IN THE WORLD! | |
// | |
// Written by Shell-Shoccar Japan (@shellshoccarjpn) on 2025-05-25 | |
// | |
////////////////////////////////////////////////////////////////////// | |
bool waitill(unsigned long millisec_to_ret); | |
unsigned long WT_EPOCH; // To set the reference time (epoch time) | |
unsigned long t; // To set the milliseconds after the WT_EPOCH | |
// (It is for the argument for waitill()) | |
void setup() { | |
pinMode(13,OUTPUT); // LED pin | |
WT_EPOCH = millis(); | |
t = 0; | |
} | |
void loop() { | |
digitalWrite(13,HIGH); | |
t += 500; // Set the next end time for the waitill(), | |
waitill(t); // then call it. | |
digitalWrite(13,LOW ); | |
t += 500; // Set the next end time for the waitill(), | |
waitill(t); // then call it. | |
} | |
bool waitill(unsigned long millisec_to_ret) { | |
unsigned long dt; | |
dt = millis() - WT_EPOCH; | |
if (millisec_to_ret > dt) {delay(millisec_to_ret-dt);} | |
return true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment