#!/usr/bin/env bash
declare -A pinyin=(
  [甲]='jiă'
  [乙]='yĭ'
  [丙]='bĭng'
  [丁]='dīng'
  [戊]='wù'
  [己]='jĭ'
  [庚]='gēng'
  [辛]='xīn'
  [壬]='rén'
  [癸]='gŭi'

  [子]='zĭ'
  [丑]='chŏu'
  [寅]='yín'
  [卯]='măo'
  [辰]='chén'
  [巳]='sì'
  [午]='wŭ'
  [未]='wèi'
  [申]='shén'
  [酉]='yŏu'
  [戌]='xū'
  [亥]='hài'
)

celestial=(甲 乙 丙 丁 戊 己 庚 辛 壬 癸)
terrestrial=(子 丑 寅 卯 辰 巳 午 未 申 酉 戌 亥)
animals=(Rat   Ox   Tiger  Rabbit  Dragon Snake
         Horse Goat Monkey Rooster Dog    Pig)
elements=(Wood Fire Earth Metal Water)
aspects=(yang yin)

BaseYear=4

function main {
  if (( !$# )); then
    set -- $(date +%Y)
  fi
  local year
  for year; do
    if (( $# > 1 )); then
      printf '%s:' "$year"
    fi
    local -i cycle_year=year-BaseYear
    local -i stem_number=$cycle_year%${#celestial[@]}
    local stem_han=${celestial[$stem_number]}
    local stem_pinyin=${pinyin[$stem_han]}

    local -i element_number=stem_number/2
    local element=${elements[$element_number]}

    local -i branch_number=$cycle_year%${#terrestrial[@]}
    local branch_han=${terrestrial[$branch_number]}
    local branch_pinyin=${pinyin[$branch_han]}
    local animal=${animals[$branch_number]}

    local -i aspect_number=$cycle_year%${#aspects[@]}
    local aspect=${aspects[$aspect_number]}

    printf '%s%s'  $stem_han $branch_han
    printf '(%s-%s, %s %s; %s)\n' $stem_pinyin $branch_pinyin $element $animal $aspect
  done
}

main "[email protected]"


···
http://rosettacode.org/wiki/Chinese_zodiac
···
■ ChineseZodiac
  § static
    tiangan⦂ String[][]: ¤ · 10 celestial stems
     ¤ "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"
     ¤ "jiă", "yĭ", "bĭng", "dīng", "wù", "jĭ", "gēng", "xīn", "rén", "gŭi"

    dizhi⦂ String[][]: ¤ · 12 terrestrial branches
     ¤ "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"
     ¤ "zĭ", "chŏu", "yín", "măo", "chén", "sì", "wŭ", "wèi", "shēn", "yŏu", "xū", "hài"

    wuxing⦂ String[][]: ¤ · 5 traditional elements
     ¤ "木", "火", "土", "金", "水"
     ¤ "mù", "huǒ", "tǔ", "jīn", "shuǐ"
     ¤ "wood", "fire", "earth", "metal", "water"

    shengxiao⦂ String[][]: ¤ · 12 animal deities
     ¤ "鼠", "牛", "虎", "兔", "龍", "蛇", "馬", "羊", "猴", "鸡", "狗", "豬"
     ¤ "shǔ", "niú", "hǔ", "tù", "lóng", "shé", "mǎ", "yáng", "hóu", "jī", "gǒu", "zhū"
     ¤ "rat", "ox", "tiger", "rabbit", "dragon", "snake", "horse", "goat", "monkey", "rooster", "dog", "pig"

    yinyang⦂ String[][]: ¤ · 2 fundamental principles
     ¤ "阳", "阴"
     ¤ "yáng", "yīn"

    ▶ main
    • args⦂ String[]
      for each year ∈ [1935, 1938, 1968, 1972, 1976, 1984, 1985, 1986, 2017]⦂ int
          cycle⦂  int: year - 4
          stem⦂   int: cycle \ 10
          branch⦂ int: cycle \ 12
          System.out.printf "%4s  %-8s %-6s %-6s %s\n", year, tiangan[0][stem] ⊕ dizhi[0][branch],
            wuxing[0][stem / 2], shengxiao[0][branch], yinyang[0][year \ 2]
          System.out.printf "      %-9s %-7s %-7s %s\n", tiangan[1][stem] ⊕ dizhi[1][branch],
            wuxing[1][stem / 2], shengxiao[1][branch], yinyang[1][year \ 2]
          System.out.printf "      %-2s/60     %-7s %s\n\n", cycle \ 60 + 1,
            wuxing[2][stem / 2], shengxiao[2][branch]


' Chinese zodiac - VBS

Animals  = array( "Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig" )
Elements = array( "Wood","Fire","Earth","Metal","Water" )
YinYang  = array( "Yang","Yin" )
Years    = array( 1935, 1938, 1968, 1972, 1976, 1984, 2017 )

for i = LBound(Years) to UBound(Years)
	xYear    = Years(i)
	yElement = Elements(((xYear - 4) mod 10) \ 2)
	yAnimal  = Animals(  (xYear - 4) mod 12     )
	yYinYang = YinYang(   xYear      mod  2     )
	nn       =          ((xYear - 4) mod 60) + 1
	msgbox xYear & " is the year of the " & yElement & " " &  yAnimal & " (" &  yYinYang & ").",, _
		   xYear & " : " & nn & "/60"
next


Module Module1

    ReadOnly ANIMALS As String() = {"Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"}
    ReadOnly ELEMENTS As String() = {"Wood", "Fire", "Earth", "Metal", "Water"}
    ReadOnly ANIMAL_CHARS As String() = {"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"}
    ReadOnly ELEMENT_CHARS As String(,) = {{"甲", "丙", "戊", "庚", "壬"}, {"乙", "丁", "己", "辛", "癸"}}

    Function GetYY(year As Integer) As String
        If year Mod 2 = 0 Then
            Return "yang"
        End If
        Return "yin"
    End Function

    Sub Main()
        Console.OutputEncoding = System.Text.Encoding.UTF8
        Dim years = {1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017}
        For i = 0 To years.Length - 1
            Dim t0 = years(i)
            Dim t1 = t0 - 4.0
            Dim t2 = t1 Mod 10
            Dim t3 = t2 / 2
            Dim t4 = Math.Floor(t3)

            Dim ei As Integer = Math.Floor(((years(i) - 4.0) Mod 10) / 2)
            Dim ai = (years(i) - 4) Mod 12
            Console.WriteLine("{0} is the year of the {1} {2} ({3}). {4}{5}", years(i), ELEMENTS(ei), ANIMALS(ai), GetYY(years(i)), ELEMENT_CHARS(years(i) Mod 2, ei), ANIMAL_CHARS((years(i) - 4) Mod 12))
        Next
    End Sub

End Module


const (
    animal_string = ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
        "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"]
    stem_yy_string  = ["Yang", "Yin"]
    element_string = ["Wood", "Fire", "Earth", "Metal", "Water"]
    stem_ch        = "甲乙丙丁戊己庚辛壬癸".split('')
    branch_ch      = "子丑寅卯辰巳午未申酉戌亥".split('')
)

fn cz(y int) (string, string, string, string, int) {
    yr := y-4
    stem := yr % 10
    branch := yr % 12
    return animal_string[branch],
        stem_yy_string[stem%2],
        element_string[stem/2],
        [stem_ch[stem], branch_ch[branch]].join(''),
        yr%60 + 1
}

fn main() {
    for yr in [1935, 1938, 1968, 1972, 1976] {
        a, yy, e, sb, cy := cz(yr)
        println("$yr: $e $a, $yy, Cycle year $cy $sb")
    }
}


import "/fmt" for Fmt

class ChineseZodiac {
    static init() {
        __animals  = ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
            "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"]
        __aspects  = ["Yang","Yin"]
        __elements = ["Wood", "Fire", "Earth", "Metal", "Water"]
        __stems    = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"]
        __branches = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]
        __sNames   = ["jiă", "yĭ", "bĭng", "dīng", "wù", "jĭ", "gēng", "xīn", "rén", "gŭi"]
        __bNames   = ["zĭ", "chŏu", "yín", "măo", "chén", "sì", "wŭ", "wèi", "shēn", "yŏu",  "xū", "hài"]
    }

    construct new(year) {
        var y = year - 4
        var s = y % 10
        var b = y % 12
        _year    = year
        _stem    = __stems[s]
        _branch  = __branches[b]
        _sName   = __sNames[s]
        _bName   = __bNames[b]
        _element = __elements[(s/2).floor]
        _animal  = __animals[b]
        _aspect  = __aspects[s % 2]
        _cycle   = y % 60 + 1
    }

    toString {
        var name = Fmt.s(-9, _sName + "-" + _bName)
        var elem = Fmt.s(-7, _element)
        var anim = Fmt.s(-7, _animal)
        var aspt = Fmt.s(-6, _aspect)
        var cycl = Fmt.dz(2, _cycle) + "/60"
        return "%(_year)    %(_stem)%(_branch)   %(name)  %(elem)  %(anim)   %(aspt) %(cycl)"
    }
}

var years = [1935, 1938, 1968, 1972, 1976, 1984, 2017, 2020]
System.print("Year  Chinese  Pinyin     Element  Animal   Aspect  Cycle")
System.print("----  -------  ---------  -------  -------  ------  -----")
ChineseZodiac.init()
for (year in years) System.print(ChineseZodiac.new(year))


dim Animals$(12) : for a = 0 to 11 : read Animals$(a) : next a
dim Elements$(5) : for a = 0 to 4  : read Elements$(a): next a
dim YinYang$(2)  : for a = 0 to 1  : read YinYang$(a) : next a
dim Years(7)     : for a = 0 to 6  : read Years(a)    : next a

for i = 0 to arraysize(Years(),1)-1
	xYear    = Years(i)
	yElement$ = Elements$((Mod((xYear - 4), 10)) / 2)
	yAnimal$  = Animals$(  Mod((xYear - 4), 12))
	yYinYang$ = YinYang$(  Mod(xYear, 2)       )
	nn        =         (  Mod((xYear - 4), 60)) + 1
	print xYear, " is the year of the ", yElement$, " ",  yAnimal$, " (", yYinYang$, ")."
next i
print
end

data "Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"
data "Wood","Fire","Earth","Metal","Water"
data "Yang","Yin"
data 1935, 1938, 1968, 1972, 1976, 1984, 2017


fcn ceToChineseZodiac(ce_year){	// --> list of strings
   # encoding: utf-8
   var [const] pinyin=SD(  // create some static variables, SD is small fixed dictionary
     "甲","jiă",  "乙","yĭ",  "丙","bĭng", "丁","dīng", "戊","wù", "己","jĭ",
     "庚","gēng", "辛","xīn", "壬","rén",  "癸","gŭi",

     "子","zĭ",  "丑","chŏu", "寅","yín", "卯","măo",  "辰","chén", "巳","sì",
     "午","wŭ",  "未","wèi",  "申","shén","酉","yŏu",  "戌","xū",   "亥","hài"
   ),

   celestial  =T("甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"),
   terrestrial=T("子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"),
   animals    =T("Rat",   "Ox",   "Tiger",  "Rabbit",  "Dragon", "Snake",
		 "Horse", "Goat", "Monkey", "Rooster", "Dog",    "Pig"),
   elements   =T("Wood", "Fire", "Earth", "Metal", "Water"),
   aspects    =T("yang","yin"),
   ;

   const BASE=4;

   cycle_year:=ce_year - BASE;

   cycle_year,aspect    := ce_year - BASE,         aspects[cycle_year%2];
   stem_number,element  := cycle_year%10,          elements[stem_number/2];
   stem_han,stem_pinyin := celestial[stem_number], pinyin[stem_han];

   branch_number,animal     := cycle_year%12,      animals[branch_number];
   branch_han,branch_pinyin := terrestrial[branch_number], pinyin[branch_han];

   return(stem_han,branch_han,
	  stem_pinyin,branch_pinyin, element,animal,aspect)
}


LDA $D011                ;screen control register 1
AND #%00100000           ;bit 5 clear = text mode, bit 5 set = gfx mode
BEQ isTerminal


with Ada.Text_IO;          use Ada.Text_IO;
with Interfaces.C_Streams; use Interfaces.C_Streams;

procedure Test_tty is
begin
   if Isatty(Fileno(Stdout)) = 0 then
      Put_Line(Standard_Error, "stdout is not a tty.");
   else
      Put_Line(Standard_Error, "stdout is a tty.");
   end if;
end Test_tty;


#include <unistd.h>   // for isatty()
#include <stdio.h>    // for fileno()

int main()
{
    puts(isatty(fileno(stdout))
          ? "stdout is tty"
          : "stdout is not tty");
    return 0;
}


using System;

namespace CheckTerminal {
    class Program {
        static void Main(string[] args) {
            Console.WriteLine("Stdout is tty: {0}", Console.IsOutputRedirected);
        }
    }
}


#if _WIN32
#include <io.h>
#define ISATTY _isatty
#define FILENO _fileno
#else
#include <unistd.h>
#define ISATTY isatty
#define FILENO fileno
#endif

#include <iostream>

int main() {
    if (ISATTY(FILENO(stdout))) {
        std::cout << "stdout is a tty\n";
    } else {
        std::cout << "stdout is not a tty\n";
    }

    return 0;
}


      *>
      *> istty, check id fd 0 is a tty
      *> Tectonics: cobc -xj istty.cob
      *>            echo "test" | ./istty
      *>
       identification division.
       program-id. istty.

       data division.
       working-storage section.
       01 rc usage binary-long.

       procedure division.
       sample-main.

       call "isatty" using by value 0 returning rc
       display "fd 0 tty: " rc

       call "isatty" using by value 1 returning rc
       display "fd 1 tty: " rc upon syserr

       call "isatty" using by value 2 returning rc
       display "fd 2 tty: " rc

       goback.
       end program istty.


(with-open-stream (s *standard-output*)
  (format T "stdout is~:[ not~;~] a terminal~%"
          (interactive-stream-p s)))


File.new("testfile").tty?   #=> false
File.new("/dev/tty").tty?   #=> true
STDOUT.tty?  #=> true


import std.stdio;

extern(C) int isatty(int);

void main() {
    writeln("Stdout is tty: ", stdout.fileno.isatty == 1);
}


IN: scratchpad USE: unix.ffi
IN: scratchpad 1 isatty

--- Data stack:
1


Open Cons For Output As #1
' Open Cons abre los flujos de entrada (stdin) o salida (stdout) estándar
' de la consola para leer o escribir.

If Err > 0 Then
    Print #1, "stdout is not a tty."
Else
    Print #1, "stdout is a tty."
End If
Close #1
Sleep


package main

import (
    "os"
    "fmt"
)

func main() {
    if fileInfo, _ := os.Stdout.Stat(); (fileInfo.Mode() & os.ModeCharDevice) != 0 {
        fmt.Println("Hello terminal")
    } else {
        fmt.Println("Who are you? You're not a terminal")
    }
}


module Main where

-- requires the unix package
-- https://hackage.haskell.org/package/unix
import System.Posix.Terminal (queryTerminal)
import System.Posix.IO (stdOutput)

main :: IO ()
main = do
  istty <- queryTerminal stdOutput
  putStrLn
    (if istty
       then "stdout is tty"
       else "stdout is not tty")


node -p -e "Boolean(process.stdout.isTTY)"
true


if isa(STDOUT, Base.TTY)
    println("This program sees STDOUT as a TTY.")
else
    println("This program does not see STDOUT as a TTY.")
end


// Kotlin Native version 0.5

import platform.posix.*

fun main(args: Array<String>) {
    if (isatty(STDOUT_FILENO) != 0)
        println("stdout is a terminal")
    else
        println("stdout is not a terminal")
}


local function isTTY ( fd )
    fd = tonumber( fd ) or 1
    local ok, exit, signal = os.execute( string.format( "test -t %d", fd ) )
    return (ok and exit == "exit") and signal == 0 or false
end

print( "stdin", isTTY( 0 ) )
print( "stdout", isTTY( 1 ) )
print( "stderr", isTTY( 2 ) )


def isTerm = System.Console.IsOutputRedirected;


import terminal

stderr.write if stdout.isatty: "stdout is a terminal\n" else: "stdout is not a terminal\n"


let () =
  print_endline (
    if Unix.isatty Unix.stdout
    then "Output goes to tty."
    else "Output doesn't go to tty."
  )


(define (isatty? fd) (syscall 16 fd 19))
(print (if (isatty? stdout)
   "stdout is a tty."
   "stdout is not a tty."))


$ perl -e "warn -t STDOUT ? 'Terminal' : 'Other'"
Terminal
$ perl -e "warn -t STDOUT ? 'Terminal' : 'Other'" > x.tmp
Other


without js -- (no input or output redirection in a browser!)
printf(1,"stdin:%t, stdout:%t, stderr:%t\n",{isatty(0),isatty(1),isatty(2)})


if(posix_isatty(STDOUT)) {
    echo "The output device is a terminal".PHP_EOL;
} else {
    echo "The output device is NOT a terminal".PHP_EOL;
}


from sys import stdout
if stdout.isatty():
    print 'The output device is a teletype. Or something like a teletype.'
else:
    print 'The output device isn\'t like a teletype.'


  [ $ |from sys import stdout
to_stack( 1 if stdout.isatty() else 0)|
    python ]                            is ttyout ( --> b )

  ttyout if
    [ say "Looks like a teletype." ]
  else
    [ say "Not a teletype." ]


$ raku -e 'note $*OUT.t'
True
$ raku -e 'note $*OUT.t' >/dev/null
False


/*REXX program determines if the   STDIN   is a   terminal device   or  other.          */
signal on syntax                                 /*if syntax error, then jump ──► SYNTAX*/
say  'output device:'  testSTDIN()               /*displays   terminal   ──or──   other */
exit 0                                           /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
testSTDIN: syntax.=1;  signal .; .: z.= sigl;  call linein ,2; ..:  syntax.= 0; return z..
                                                 /* [↑]  must/should be all on one line.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
syntax:  z..= 'other'                            /*when a SYNTAX error occurs, come here*/
if syntax.  then do                              /*are we handling  STDIN  thingy error?*/
                 if sigl==z.  then z..= 'terminal';    signal ..     /*is this a stdin ?*/
                 end                             /* [↑]   can't use a   RETURN   here.  */

                                 /*    ···  handle other REXX syntax errors here  ···   */


f = File.open("test.txt")
p f.isatty          # => false
p STDOUT.isatty     # => true


/* Uses C library interface */

extern crate libc;

fn main() {
    let istty = unsafe { libc::isatty(libc::STDOUT_FILENO as i32) } != 0;
    if istty {
        println!("stdout is tty");
    } else {
        println!("stdout is not tty");
    }
}


import org.fusesource.jansi.internal.CLibrary._

object IsATty  extends App {

  var enabled = true

  def apply(enabled: Boolean): Boolean = {
    // We must be on some unix variant..
    try {
      enabled && isatty(STDOUT_FILENO) == 1
    }
    catch {
      case ignore: Throwable =>
        ignore.printStackTrace()
        false

    }
  }

    println("tty " + apply(true))
}


val stdoutRefersToTerminal : bool = Posix.ProcEnv.isatty Posix.FileSys.stdout


set toTTY [dict exists [fconfigure stdout] -mode]
puts [expr {$toTTY ? "Output goes to tty" : "Output doesn't go to tty"}]


#!/bin/sh

if [ -t 1 ]
then
   echo "Output is a terminal"
else
   echo "Output is NOT a terminal" >/dev/tty
fi


Module Module1

    Sub Main()
        Console.WriteLine("Stdout is tty: {0}", Console.IsOutputRedirected)
    End Sub

End Module


/* check_output_device_is_terminal.wren */

class C {
    foreign static isOutputDeviceTerminal
}

System.print("Output device is a terminal = %(C.isOutputDeviceTerminal)")


const S_IFCHR=0x2000;
fcn S_ISCHR(f){ f.info()[4].bitAnd(S_IFCHR).toBool() }
S_ISCHR(File.stdout).println();


with Ada.Calendar;               use Ada.Calendar;
with Ada.Numerics.Float_Random;
with Ada.Text_IO;                use Ada.Text_IO;

procedure Test_Checkpoint is

   package FR renames Ada.Numerics.Float_Random;
   No_Of_Cubicles: constant Positive := 3;
     -- That many workers can work in parallel
   No_Of_Workers: constant Positive := 6;
     -- That many workers are potentially available
     -- some will join the team when others quit the job

   type Activity_Array is array(Character) of Boolean;
     -- we want to know who is currently working

   protected Checkpoint is
      entry Deliver;
      entry Join (Label : out Character; Tolerance: out Float);
      entry Leave(Label : in Character);
   private
      Signaling     : Boolean   := False;
      Ready_Count   : Natural   := 0;
      Worker_Count  : Natural   := 0;
      Unused_Label  : Character := 'A';
      Likelyhood_To_Quit: Float := 1.0;
      Active        : Activity_Array := (others => false);
      entry Lodge;
   end Checkpoint;

   protected body Checkpoint is
      entry Join (Label : out Character; Tolerance: out Float)
      when not Signaling and Worker_Count < No_Of_Cubicles is
      begin
         Label        := Unused_Label;
         Active(Label):= True;
         Unused_Label := Character'Succ (Unused_Label);
         Worker_Count := Worker_Count + 1;
         Likelyhood_To_Quit := Likelyhood_To_Quit / 2.0;
         Tolerance    := Likelyhood_To_Quit;
      end Join;

      entry Leave(Label: in Character) when not Signaling is
      begin
         Worker_Count  := Worker_Count - 1;
         Active(Label) := False;
      end Leave;

      entry Deliver when not Signaling is
      begin
         Ready_Count := Ready_Count + 1;
         requeue Lodge;
      end Deliver;

      entry Lodge when Ready_Count = Worker_Count or Signaling is
      begin
         if Ready_Count = Worker_Count then
            Put("---Sync Point [");
            for C in Character loop
               if Active(C) then
                  Put(C);
               end if;
            end loop;
            Put_Line("]---");
         end if;
         Ready_Count := Ready_Count - 1;
         Signaling   := Ready_Count /= 0;
      end Lodge;
   end Checkpoint;

   task type Worker;

   task body Worker is
      Dice      : FR.Generator;
      Label     : Character;
      Tolerance : Float;
      Shift_End : Time := Clock + 2.0;
        -- Trade unions are hard!
   begin
      FR.Reset (Dice);
      Checkpoint.Join (Label, Tolerance);
      Put_Line(Label & " joins the team");
      loop
         Put_Line (Label & " is working");
         delay Duration (FR.Random (Dice) * 0.500);
         Put_Line (Label & " is ready");
         Checkpoint.Deliver;
         if FR.Random(Dice) < Tolerance then
            Put_Line(Label & " leaves the team");
            exit;
         elsif Clock >= Shift_End then
            Put_Line(Label & " ends shift");
            exit;
         end if;
      end loop;
      Checkpoint.Leave(Label);
   end Worker;
   Set : array (1..No_Of_Workers) of Worker;
begin
   null; -- Nothing to do here
end Test_Checkpoint;


      INSTALL @lib$+"TIMERLIB"
      nWorkers% = 3
      DIM tID%(nWorkers%)

      tID%(1) = FN_ontimer(10, PROCworker1, 1)
      tID%(2) = FN_ontimer(11, PROCworker2, 1)
      tID%(3) = FN_ontimer(12, PROCworker3, 1)

      DEF PROCworker1 : PROCtask(1) : ENDPROC
      DEF PROCworker2 : PROCtask(2) : ENDPROC
      DEF PROCworker3 : PROCtask(3) : ENDPROC

      ON ERROR PROCcleanup : REPORT : PRINT : END
      ON CLOSE PROCcleanup : QUIT

      REPEAT
        WAIT 0
      UNTIL FALSE
      END

      DEF PROCtask(worker%)
      PRIVATE cnt%()
      DIM cnt%(nWorkers%)
      CASE cnt%(worker%) OF
        WHEN 0:
          cnt%(worker%) = RND(30)
          PRINT "Worker "; worker% " starting (" ;cnt%(worker%) " ticks)"
        WHEN -1:
        OTHERWISE:
          cnt%(worker%) -= 1
          IF cnt%(worker%) = 0 THEN
            PRINT "Worker "; worker% " ready and waiting"
            cnt%(worker%) = -1
            PROCcheckpoint
            cnt%(worker%) = 0
          ENDIF
      ENDCASE
      ENDPROC

      DEF PROCcheckpoint
      PRIVATE checked%, sync%
      IF checked% = 0 sync% = FALSE
      checked% += 1
      WHILE NOT sync%
        WAIT 0
        IF checked% = nWorkers% THEN
          sync% = TRUE
          PRINT "--Sync Point--"
        ENDIF
      ENDWHILE
      checked% -= 1
      ENDPROC

      DEF PROCcleanup
      LOCAL I%
      FOR I% = 1 TO nWorkers%
        PROC_killtimer(tID%(I%))
      NEXT
      ENDPROC


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <omp.h>

int main()
{
        int jobs = 41, tid;
        omp_set_num_threads(5);

        #pragma omp parallel shared(jobs) private(tid)
        {
                tid = omp_get_thread_num();
                while (jobs > 0) {
                        /* this is the checkpoint */
                        #pragma omp barrier
                        if (!jobs) break;

                        printf("%d: taking job %d\n", tid, jobs--);
                        usleep(100000 + rand() / (double) RAND_MAX * 3000000);
                        printf("%d: done job\n", tid);
                }

                printf("[%d] leaving\n", tid);

                /* this stops jobless thread from exiting early and killing workers */
                #pragma omp barrier
        }

        return 0;
}


#include <iostream>
#include <chrono>
#include <atomic>
#include <mutex>
#include <random>
#include <thread>

std::mutex cout_lock;

class Latch
{
    std::atomic<int> semafor;
  public:
    Latch(int limit) : semafor(limit) {}

    void wait()
    {
        semafor.fetch_sub(1);
        while(semafor.load() > 0)
            std::this_thread::yield();
    }
};

struct Worker
{
    static void do_work(int how_long, Latch& barrier, std::string name)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(how_long));
        {   std::lock_guard<std::mutex> lock(cout_lock);
            std::cout << "Worker " << name << " finished work\n";   }
        barrier.wait();
        {   std::lock_guard<std::mutex> lock(cout_lock);
            std::cout << "Worker " << name << " finished assembly\n";   }
    }
};

int main()
{
    Latch latch(5);
    std::mt19937 rng(std::random_device{}());
    std::uniform_int_distribution<> dist(300, 3000);
    std::thread threads[] {
        std::thread(&Worker::do_work, dist(rng), std::ref(latch), "John"),
        std::thread{&Worker::do_work, dist(rng), std::ref(latch), "Henry"},
        std::thread{&Worker::do_work, dist(rng), std::ref(latch), "Smith"},
        std::thread{&Worker::do_work, dist(rng), std::ref(latch), "Jane"},
        std::thread{&Worker::do_work, dist(rng), std::ref(latch), "Mary"},
    };
    for(auto& t: threads) t.join();
    std::cout << "Assembly is finished";
}


(ns checkpoint.core
  (:gen-class)
  (:require [clojure.core.async :as async :refer [go <! >! <!! >!! alts! close!]]
            [clojure.string :as string]))

(defn coordinate [ctl-ch resp-ch combine]
  (go
    (<! (async/timeout 2000)) ;delay a bit to allow worker setup
    (loop [members {}, received {}] ;maps by in-channel of out-channels & received data resp.
      (let [rcvd-count (count received)
            release   #(doseq [outch (vals members)] (go (>! outch %)))
            received  (if (and (pos? rcvd-count) (= rcvd-count (count members)))
                        (do (-> received vals combine release) {})
                        received)
            [v ch] (alts! (cons ctl-ch (keys members)))]
              ;receive a message on ctrl-ch or any member input channel
        (if (= ch ctl-ch)
          (let [[op inch outch] v] ;only a Checkpoint (see below) sends on ctl-ch
            (condp = op
              :join (do (>! resp-ch :ok)
                        (recur (assoc members inch outch) received))
              :part (do (>! resp-ch :ok)
                        (close! inch) (close! outch)
                        (recur (dissoc members inch) (dissoc received inch)))
              :exit :exit))
          (if (nil? v) ;is the channel closed?
            (do
              (close! (get members ch))
              (recur (dissoc members ch) (dissoc received ch)))
            (recur members (assoc received ch v))))))))

(defprotocol ICheckpoint
  (join [this])
  (part [this inch outch]))

(deftype Checkpoint [ctl-ch resp-ch sync]
  ICheckpoint
  (join [this]
    (let [inch (async/chan), outch (async/chan 1)]
      (go
        (>! ctl-ch [:join inch outch])
        (<! resp-ch)
        [inch outch])))
  (part [this inch outch]
    (go
      (>! ctl-ch [:part inch outch]))))

(defn checkpoint [combine]
  (let [ctl-ch (async/chan), resp-ch (async/chan 1)]
    (->Checkpoint ctl-ch resp-ch (coordinate ctl-ch resp-ch combine))))

(defn worker
  ([ckpt repeats] (worker ckpt repeats (fn [& args] nil)))
  ([ckpt repeats mon]
    (go
      (let [[send recv] (<! (join ckpt))]
        (doseq [n (range repeats)]
          (<! (async/timeout (rand-int 5000)))
          (>! send n) (mon "sent" n)
          (<! recv)  (mon "recvd"))
        (part ckpt send recv)))))

(defn -main
  [& args]
  (let [ckpt (checkpoint identity)
        monitor (fn [id]
                  (fn [& args] (println (apply str "worker" id ":" (string/join " " args)))))]
    (worker ckpt 10 (monitor 1))
    (worker ckpt 10 (monitor 2))))


import std.stdio;
import std.parallelism: taskPool, defaultPoolThreads, totalCPUs;

void buildMechanism(uint nparts) {
    auto details = new uint[nparts];
    foreach (i, ref detail; taskPool.parallel(details)) {
        writeln("Build detail ", i);
        detail = i;
    }

    // This could be written more concisely via std.parallelism.reduce,
    // but we want to see the checkpoint explicitly.
    writeln("Checkpoint reached. Assemble details ...");
    uint sum = 0;
    foreach (immutable detail; details)
        sum += detail;
    writeln("Mechanism with ", nparts, " parts finished: ", sum);
}

void main() {
    defaultPoolThreads = totalCPUs + 1; // totalCPUs - 1 on default.
    buildMechanism(42);
    buildMechanism(11);
}


/** A flagSet solves this problem: There are N things, each in a true or false
  * state, and we want to know whether they are all true (or all false), and be
  * able to bulk-change all of them, and all this without allowing double-
  * counting -- setting a flag twice is idempotent.
  */
def makeFlagSet() {
  # Each flag object is either in the true set or the false set.
  def trues := [].asSet().diverge()
  def falses := [].asSet().diverge()
  return def flagSet {
    /** Add a flag to the set. */
    to join() {
      def flag {
        /** Get the value of this flag. */
        to get() :boolean {

        }
        /** Set the value of this flag. */
        to put(v :boolean) {
          def [del,add] := if (v) { [falses,trues] } else { [trues,falses] }
          if (del.contains(flag)) {
            del.remove(flag)
            add.addElement(flag)
          }
        }
        /** Remove this flag from the set. */
        to leave() :void {
          trues.remove(flag)
          falses.remove(flag)
        }
      }
      falses.addElement(flag)
      return flag
    }
    /** Are all the flags true (none false)? */
    to allTrue() { return falses.size().isZero() }
    /** Are all the flags false (none true)? */
    to allFalse() { return trues.size().isZero() }
    /** Set all the flags to the same value. */
    to setAll(v :boolean) {
      def [del,add] := if (v) { [falses,trues] } else { [trues,falses] }
      add.addAll(del)
      del.removeAll(del)
    }
  }
}

def makeCheckpoint() {
  def [var continueSignal, var continueRes] := Ref.promise()
  def readies := makeFlagSet()

  /** Check whether all tasks have reached the checkpoint, and if so send the
    * signal and go to the next round. */
  def check() {
    if (readies.allTrue()) {
      readies.setAll(false)

      continueRes.resolve(null)    # send the continue signal

      def [p, r] := Ref.promise()  # prepare a new continue signal
      continueSignal := p
      continueRes := r
    }
  }

  return def checkpoint {
    to join() {
      def &flag := readies.join()
      return def membership {
        to leave() {
          (&flag).leave()
          check <- ()
        }
        to deliver() {
          flag := true
          check <- ()
          return continueSignal
        }
      }
    }
  }
}

def makeWorker(piece, checkpoint) {
  def stops := timer.now() + 3000 + entropy.nextInt(2000)
  var count := 0
  def checkpointMember := checkpoint <- join()
  def stopped
  def run() {
    # Pretend to do something lengthy; up to 1000 ms.
    timer.whenPast(timer.now() + entropy.nextInt(1000), fn {
      if (timer.now() >= stops) {
        checkpointMember <- leave()
        bind stopped := true
      } else {
        count += 1
        println(`Delivering $piece#$count`)
        when (checkpointMember <- deliver()) -> {
          println(`Delivered $piece#$count`)
          run()
        }
      }
    })
  }
  run()
  return stopped
}

def checkpoint := makeCheckpoint()
var waits := []
for piece in 1..5 {
  waits with= makeWorker(piece, checkpoint)
}
interp.waitAtTop(promiseAllFulfilled(waits))


-module( checkpoint_synchronization ).

-export( [task/0] ).

task() ->
      Pid = erlang:spawn( fun() -> checkpoint_loop([], []) end ),
      [erlang:spawn(fun() -> random:seed(X, 1, 0), worker_loop(X, 3, Pid) end) || X <- lists:seq(1, 5)],
      erlang:exit( Pid, normal ).

checkpoint_loop( Assemblings, Completes ) ->
        receive
        {starting, Worker} -> checkpoint_loop( [Worker | Assemblings], Completes );
        {done, Worker} ->
               New_assemblings = lists:delete( Worker, Assemblings ),
               New_completes = checkpoint_loop_release( New_assemblings, [Worker | Completes] ),
               checkpoint_loop( New_assemblings, New_completes )
        end.

checkpoint_loop_release( [], Completes ) ->
        [X ! all_complete || X <- Completes],
        [];
checkpoint_loop_release( _Assemblings, Completes ) -> Completes.

worker_loop( _Worker, 0, _Checkpoint ) -> ok;
worker_loop( Worker, N, Checkpoint ) ->
        Checkpoint ! {starting, erlang:self()},
        io:fwrite( "Worker ~p ~p~n", [Worker, N] ),
        timer:sleep( random:uniform(100) ),
        Checkpoint ! {done, erlang:self()},
        receive
        all_complete -> ok
        end,
        worker_loop( Worker, N - 1, Checkpoint ).


#include "ontimer.bi"

Randomize Timer
Dim Shared As Uinteger nWorkers = 3
Dim Shared As Uinteger tID(nWorkers)
Dim Shared As Integer cnt(nWorkers)
Dim Shared As Integer checked = 0

Sub checkpoint()
    Dim As Boolean sync

    If checked = 0 Then sync = False
    checked += 1
    If (sync = False) And (checked = nWorkers) Then
        sync = True
        Color 14 : Print "--Sync Point--"
        checked = 0
    End If
End Sub

Sub task(worker As Uinteger)
    Redim Preserve cnt(nWorkers)

    Select Case cnt(worker)
    Case 0
        cnt(worker) = Rnd * 3
        Color 15 : Print "Worker " & worker & " starting (" & cnt(worker) & " ticks)"
    Case -1
        Exit Select
    Case Else
        cnt(worker) -= 1
        If cnt(worker) = 0 Then
            Color 7 : Print "Worker "; worker; " ready and waiting"
            cnt(worker) = -1
            checkpoint
            cnt(worker) = 0
        End If
    End Select
End Sub

Sub worker1
    task(1)
End Sub
Sub worker2
    task(2)
End Sub
Sub worker3
    task(3)
End Sub

Do
    OnTimer(500, @worker1, 1)
    OnTimer(100, @worker2, 1)
    OnTimer(900, @worker3, 1)
    Sleep 1000
Loop


package main

import (
    "log"
    "math/rand"
    "sync"
    "time"
)

func worker(part string) {
    log.Println(part, "worker begins part")
    time.Sleep(time.Duration(rand.Int63n(1e6)))
    log.Println(part, "worker completes part")
    wg.Done()
}

var (
    partList    = []string{"A", "B", "C", "D"}
    nAssemblies = 3
    wg          sync.WaitGroup
)

func main() {
    rand.Seed(time.Now().UnixNano())
    for c := 1; c <= nAssemblies; c++ {
        log.Println("begin assembly cycle", c)
        wg.Add(len(partList))
        for _, part := range partList {
            go worker(part)
        }
        wg.Wait()
        log.Println("assemble.  cycle", c, "complete")
    }
}


import Control.Parallel

data Task a = Idle | Make a
type TaskList a = [a]
type Results a = [a]
type TaskGroups a = [TaskList a]
type WorkerList a = [Worker a]
type Worker a = [Task a]

-- run tasks in parallel and collect their results
-- the function doesn't return until all tasks are done, therefore
-- finished threads wait for the others to finish.
runTasks :: TaskList a -> Results a
runTasks [] = []
runTasks (x:[]) = x : []
runTasks (x:y:[]) = y `par` x : y : []
runTasks (x:y:ys) = y `par` x : y : runTasks ys

-- take a list of workers with different numbers of tasks and group
-- them: first the first task of each worker, then the second one etc.
groupTasks :: WorkerList a -> TaskGroups a
groupTasks [] = []
groupTasks xs
    | allWorkersIdle xs = []
    | otherwise =
        concatMap extractTask xs : groupTasks (map removeTask xs)

-- return a task as a plain value
extractTask :: Worker a -> [a]
extractTask [] = []
extractTask (Idle:_) = []
extractTask (Make a:_) = [a]

-- remove the foremost task of each worker
removeTask :: Worker a -> Worker a
removeTask = drop 1

-- checks whether all workers are idle in this task
allWorkersIdle :: WorkerList a -> Bool
allWorkersIdle = all null . map extractTask

-- the workers must calculate big sums. the first sum of each worker
-- belongs to the first task, and so on.
-- because of laziness, nothing is computed yet.

-- worker1 has 5 tasks to do
worker1 :: Worker Integer
worker1 = map Make [ sum [1..n*1000000] | n <- [1..5] ]

-- worker2 has 4 tasks to do
worker2 :: Worker Integer
worker2 = map Make [ sum [1..n*100000] | n <- [1..4] ]

-- worker3 has 3 tasks to do
worker3 :: Worker Integer
worker3 = map Make [ sum [1..n*1000000] | n <- [1..3] ]

-- worker4 has 5 tasks to do
worker4 :: Worker Integer
worker4 = map Make [ sum [1..n*300000] | n <- [1..5] ]

-- worker5 has 4 tasks to do, but starts at the second task.
worker5 :: Worker Integer
worker5 = [Idle] ++ map Make [ sum [1..n*400000] | n <- [1..4] ]

-- group the workers' tasks
tasks :: TaskGroups Integer
tasks = groupTasks [worker1, worker2, worker3, worker4, worker5]

-- a workshop: take a function to operate the results and a group of tasks,
-- execute the tasks showing the process and process the results
workshop :: (Show a, Num a, Show b, Num b) => ([a] -> b) -> [[a]] -> IO ()
workshop func a = mapM_ doWork $ zip [1..length a] a
    where
        doWork (x, y) = do
            putStrLn $ "Doing task " ++ show x ++ "."
            putStrLn $ "There are " ++ show (length y) ++ " workers for this task."
            putStrLn "Waiting for all workers..."
            print $ func $ runTasks y
            putStrLn $ "Task " ++ show x ++ " done."

main = workshop sum tasks


global nWorkers, workers, cv

procedure main(A)
    nWorkers := integer(A[1]) | 3
    cv  := condvar()
    every put(workers := [], worker(!nWorkers))
    every wait(!workers)
end

procedure worker(n)
    return thread every !3 do {       # Union limits each worker to 3 pieces
        write(n," is working")
        delay(?3 * 1000)
        write(n," is done")
        countdown()
        }
end

procedure countdown()
    critical cv: {
        if (nWorkers -:= 1) <= 0 then {
            write("\t\tAll done")
            nWorkers := *workers
            return (unlock(cv),signal(cv, 0))
            }
        wait(cv)
        }
end


import java.util.Scanner;
import java.util.Random;

public class CheckpointSync{
	public static void main(String[] args){
		System.out.print("Enter number of workers to use: ");
		Scanner in = new Scanner(System.in);
		Worker.nWorkers = in.nextInt();
		System.out.print("Enter number of tasks to complete:");
		runTasks(in.nextInt());
	}

	/*
	 * Informs that workers started working on the task and
	 * starts running threads. Prior to proceeding with next
	 * task syncs using static Worker.checkpoint() method.
	 */
	private static void runTasks(int nTasks){
		for(int i = 0; i < nTasks; i++){
			System.out.println("Starting task number " + (i+1) + ".");
			runThreads();
			Worker.checkpoint();
		}
	}

	/*
	 * Creates a thread for each worker and runs it.
	 */
	private static void runThreads(){
		for(int i = 0; i < Worker.nWorkers; i ++){
			new Thread(new Worker(i+1)).start();
		}
	}

	/*
	 * Worker inner static class.
	 */
	public static class Worker implements Runnable{
		public Worker(int threadID){
			this.threadID = threadID;
		}
		public void run(){
			work();
		}

		/*
		 *  Notifies that thread started running for 100 to 1000 msec.
		 *  Once finished increments static counter 'nFinished'
		 *  that counts number of workers finished their work.
		 */
		private synchronized void work(){
			try {
				int workTime = rgen.nextInt(900) + 100;
				System.out.println("Worker " + threadID + " will work for " + workTime + " msec.");
				Thread.sleep(workTime); //work for 'workTime'
				nFinished++; //increases work finished counter
				System.out.println("Worker " + threadID + " is ready");
			} catch (InterruptedException e) {
				System.err.println("Error: thread execution interrupted");
				e.printStackTrace();
			}
		}

		/*
		 * Used to synchronize Worker threads using 'nFinished' static integer.
		 * Waits (with step of 10 msec) until 'nFinished' equals to 'nWorkers'.
		 * Once they are equal resets 'nFinished' counter.
		 */
		public static synchronized void checkpoint(){
			while(nFinished != nWorkers){
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					System.err.println("Error: thread execution interrupted");
					e.printStackTrace();
				}
			}
			nFinished = 0;
		}

		/* inner class instance variables */
		private int threadID;

		/* static variables */
		private static Random rgen = new Random();
		private static int nFinished = 0;
		public static int nWorkers = 0;
	}
}


function runsim(numworkers, runs)
    for count in 1:runs
        @sync begin
            for worker in 1:numworkers
                @async begin
                    tasktime = rand()
                    sleep(tasktime)
                    println("Worker $worker finished after $tasktime seconds")
                end
            end
        end
        println("Checkpoint reached for run $count.")
    end
    println("Finished all runs.\n")
end

const trials = [[3, 2], [4, 1], [2, 5], [7, 6]]
for trial in trials
    runsim(trial[1], trial[2])
end


// Version 1.2.41

import java.util.Random

val rgen = Random()
var nWorkers = 0
var nTasks = 0

class Worker(private val threadID: Int) : Runnable {

    @Synchronized
    override fun run() {
        try {
            val workTime = rgen.nextInt(900) + 100L  // 100..999 msec.
            println("Worker $threadID will work for $workTime msec.")
            Thread.sleep(workTime)
            nFinished++
            println("Worker $threadID is ready")
        }
        catch (e: InterruptedException) {
            println("Error: thread execution interrupted")
            e.printStackTrace()
        }
    }

    companion object {
        private var nFinished = 0

        @Synchronized
        fun checkPoint() {
            while (nFinished != nWorkers) {
                try {
                    Thread.sleep(10)
                }
                catch (e: InterruptedException) {
                    println("Error: thread execution interrupted")
                    e.printStackTrace()
                }
            }
            nFinished = 0  // reset
        }
    }
}

fun runTasks() {
    for (i in 1..nTasks) {
        println("\nStarting task number $i.")
        // Create a thread for each worker and run it.
        for (j in 1..nWorkers) Thread(Worker(j)).start()
        Worker.checkPoint()  // wait for all workers to finish the task
    }
}

fun main(args: Array<String>) {
    print("Enter number of workers to use: ")
    nWorkers = readLine()!!.toInt()
    print("Enter number of tasks to complete: ")
    nTasks = readLine()!!.toInt()
    runTasks()
}


:- object(checkpoint).

    :- threaded.

    :- public(run/3).
    :- mode(run(+integer,+integer,+float), one).
    :- info(run/3, [
        comment is 'Assemble items using a team of workers with a maximum time per item assembly.',
        arguments is ['Workers'-'Number of workers', 'Items'-'Number of items to assemble', 'Time'-'Maximum time in seconds to assemble one item']
    ]).

    :- public(run/0).
    :- mode(run, one).
    :- info(run/0, [
        comment is 'Assemble three items using a team of five workers with a maximum of 0.1 seconds per item assembly.'
    ]).

    :- uses(integer, [between/3]).
    :- uses(random,  [random/3]).

    run(Workers, Items, Time) :-
        % start the workers
        forall(
            between(1, Workers, Worker),
            threaded_ignore(worker(Worker, Items, Time))
        ),
        % assemble the items
        checkpoint_loop(Workers, Items).

    run :-
        % default values
        run(5, 3, 0.100).

    checkpoint_loop(_, 0) :-
        !,
        write('All assemblies done.'), nl.
    checkpoint_loop(Workers, Item) :-
        % wait for all threads to reach the checkpoint
        forall(
            between(1, Workers, Worker),
            threaded_wait(done(Worker, Item))
        ),
        write('Assembly of item '), write(Item), write(' done.'), nl,
        % signal the workers to procede to the next assembly
        NextItem is Item - 1,
        forall(
            between(1, Workers, Worker),
            threaded_notify(next(Worker, NextItem))
        ),
        checkpoint_loop(Workers, NextItem).

    worker(_, 0, _) :-
        !.
    worker(Worker, Item, Time) :-
        % the time necessary to assemble one item varies between 0.0 and Time seconds
        random(0.0, Time, AssemblyTime), thread_sleep(AssemblyTime),
        write('Worker '), write(Worker), write(' item '), write(Item), nl,
        % notify checkpoint that the worker have done his/her part of this item
        threaded_notify(done(Worker, Item)),
        % wait for green light to move to the next item
        NextItem is Item - 1,
        threaded_wait(next(Worker, NextItem)),
        worker(Worker, NextItem, Time).

:- end_object.


import locks
import os
import random
import strformat

const
  NWorkers = 3    # Number of workers.
  NTasks = 4      # Number of tasks.
  StopOrder = 0   # Order 0 is the request to stop.

var
  randLock: Lock                              # Lock to access random number generator.
  orders: array[1..NWorkers, Channel[int]]    # Channel to send orders to workers.
  responses: Channel[int]                     # Channel to receive responses from workers.
  working: int                                # Current number of workers actually working.
  threads: array[1..NWorkers, Thread[int]]    # Array of running threads.

#---------------------------------------------------------------------------------------------------

proc worker(num: int) {.thread.} =
  ## Worker thread.

  while true:
    # Wait for order from main thread (this is the checkpoint).
    let order = orders[num].recv
    if order == StopOrder: break
    # Get a random time to complete the task.
    var time: int
    withLock(randLock): time = rand(200..1000)
    echo fmt"Worker {num}: starting task number {order}"
    # Work on task during "time" ms.
    sleep(time)
    echo fmt"Worker {num}: task number {order} terminated after {time} ms"
    # Send message to indicate that the task is terminated.
    responses.send(num)

#---------------------------------------------------------------------------------------------------

# Initializations.
randomize()
randLock.initLock()
for num in 1..NWorkers:
  orders[num].open()
responses.open()

# Create the worker threads.
for num in 1..NWorkers:
  createThread(threads[num], worker, num)

# Send orders and wait for responses.
for task in 1..NTasks:
  echo fmt"Sending order to start task number {task}"
  # Send order (task number) to workers.
  for num in 1..NWorkers:
    orders[num].send(task)
  working = NWorkers          # All workers are now working.
  # Wait to receive responses from workers.
  while working > 0:
    discard responses.recv()  # Here, we don't care about the message content.
    dec working

# We have terminated: send stop order to workers.
echo "Sending stop order to workers."
for num in 1..NWorkers:
  orders[num].send(StopOrder)
joinThreads(threads)
echo "All workers stopped."

# Clean up.
for num in 1..NWorkers:
  orders[num].close()
responses.close()
deinitLock(randLock)


: task(n, jobs, myChannel)
   while(true) [
      System.Out "TASK " << n << " : Beginning my work..." << cr
      System sleep(1000 rand)
      System.Out "TASK " << n << " : Finish, sendind done and waiting for others..." << cr
      jobs send($jobDone) drop
      myChannel receive drop
      ] ;

: checkPoint(n, jobs, channels)
   while(true) [
      #[ jobs receive drop ] times(n)
      "CHECKPOINT : All jobs done, sending done to all tasks" println
      channels apply(#[ send($allDone) drop ])
      ] ;

: testCheckPoint(n)
| jobs channels i |
   ListBuffer init(n, #[ Channel new ]) dup freeze ->channels
   Channel new ->jobs

   #[ checkPoint(n, jobs, channels) ] &
   n loop: i [ #[ task(i, jobs, channels at(i)) ] & ] ;


#!/usr/bin/perl
use warnings;
use strict;
use v5.10;

use Socket;

my $nr_items = 3;

sub short_sleep($) {
    (my $seconds) = @_;
    select undef, undef, undef, $seconds;
}

# This is run in a worker thread.  It repeatedly waits for a character from
# the main thread, and sends a value back to the main thread.  A short
# sleep introduces random timing, just to keep us honest.

sub be_worker($$) {
    my ($socket, $value) = @_;
    for (1 .. $nr_items) {
        sysread $socket, my $dummy, 1;
        short_sleep rand 0.5;
        syswrite $socket, $value;
        ++$value;
    }

    exit;
}

# This function forks a worker and sends it a socket on which to talk to
# the main thread, as well as an initial value to work with.  It returns
# (to the main thread) a socket on which to talk to the worker.

sub fork_worker($) {
    (my $value) = @_;
    socketpair my $kidsock, my $dadsock, AF_UNIX, SOCK_STREAM, PF_UNSPEC
        or die "socketpair: $!";

    if (fork // die "fork: $!") {
        # We're the parent
        close $dadsock;
        return $kidsock;
    }
    else {
        # We're the child
        close $kidsock;
        be_worker $dadsock, $value;
        # Never returns
    }
}

# Fork two workers, send them start signals, retrieve the values they send
# back, and print them

my $alpha_sock = fork_worker 'A';
my $digit_sock = fork_worker 1;

for (1 .. $nr_items) {
    syswrite $_, 'x'   for $alpha_sock, $digit_sock;
    sysread $alpha_sock, my $alpha, 1;
    sysread $digit_sock, my $digit, 1;
    say $alpha, $digit;
}

# If the main thread were planning to run for a long time after the
# workers had terminate, it would need to reap them to avoid zombies:

wait; wait;


-- demo\rosetta\checkpoint_synchronisation.exw
without js -- task_xxx(), get_key()
constant NPARTS = 3
integer workers = 0
sequence waiters = {}
bool terminate = false

procedure checkpoint(integer task_id)
    if length(waiters)+1=NPARTS or terminate then
        printf(1,"checkpoint\n")
        for i=1 to length(waiters) do
            task_schedule(waiters[i],1)
        end for
        waiters = {}
    else
        waiters &= task_id
        task_suspend(task_id)
        task_yield()
    end if
end procedure

procedure worker(string name)
    printf(1,"worker %s running\n",{name})
    while not terminate do
        printf(1,"worker %s begins part\n",{name})
        task_delay(rnd())
        printf(1,"worker %s completes part\n",{name})
        checkpoint(task_self())
        if find(task_self(),waiters) then ?9/0 end if
        if terminate or rnd()>0.95 then exit end if
        task_delay(rnd())
    end while
    printf(1,"worker %s leaves\n",{name})
    workers -= 1
end procedure

string name = "A"

while get_key()!=#1B do -- (key escape to shut down)
    if workers<NPARTS then
        integer task_id = task_create(routine_id("worker"),{name})
        task_schedule(task_id,1)
        name[1] += 1
        workers += 1
    end if
    task_yield()
end while
printf(1,"escape keyed\n")
terminate = true
while workers>0 do
    task_yield()
end while

{} = wait_key()


(de checkpoints (Projects Workers)
   (for P Projects
      (prinl "Starting project number " P ":")
      (for
         (Staff
            (mapcar
               '((I) (worker (format I) (rand 2 5)))  # Create staff of workers
               (range 1 Workers) )
            Staff                                     # While still busy
            (filter worker Staff) ) )                 # Remove finished workers
      (prinl "Project number " P " is done.") ) )

(de worker (ID Steps)
   (co ID
      (prinl "Worker " ID " has " Steps " steps to do")
      (for N Steps
         (yield ID)
         (prinl "Worker " ID " step " N) )
      NIL ) )


#MaxWorktime=8000 ; "Workday" in msec

; Structure that each thread uses
Structure MyIO
  ThreadID.i
  Semaphore_Joining.i
  Semaphore_Release.i
  Semaphore_Deliver.i
  Semaphore_Leaving.i
EndStructure

; Array of used threads
Global Dim Comm.MyIO(0)

; Master loop synchronizing the threads via semaphores
Procedure CheckPoint()
  Protected i, j, maxthreads=ArraySize(Comm())
  Protected Worker_count, Deliver_count
  Repeat
    For i=1 To maxthreads
      With Comm(i)
        If TrySemaphore(\Semaphore_Leaving)
          Worker_count-1
        ElseIf TrySemaphore(\Semaphore_Deliver)
          Deliver_count+1
          If Deliver_count=Worker_count
            PrintN("All Workers reported in, starting next task.")
            Deliver_count=0
            For j=1 To maxthreads
              SignalSemaphore(Comm(j)\Semaphore_Release)
            Next j
          EndIf
        ElseIf TrySemaphore(\Semaphore_Joining)
          PrintN("A new Worker joined the force.")
          Worker_count+1: SignalSemaphore(\Semaphore_Release)
        ElseIf Worker_count=0
          ProcedureReturn
        EndIf
      Next i
    EndWith
  ForEver
  StartAll=0
EndProcedure

; A worker thread, all orchestrated by the Checkpoint() routine
Procedure Worker(ID)
  Protected EndTime=ElapsedMilliseconds()+#MaxWorktime, n
  With Comm(ID)
    SignalSemaphore(\Semaphore_Joining)
    Repeat
      Repeat ; Use a non-blocking semaphore check to avoid dead-locking at shutdown.
        If ElapsedMilliseconds()>EndTime
          SignalSemaphore(\Semaphore_Leaving)
          PrintN("Thread #"+Str(ID)+" is done.")
          ProcedureReturn
        EndIf
        Delay(1)
      Until TrySemaphore(\Semaphore_Release)
      n=Random(1000)
      PrintN("Thread #"+Str(ID)+" will work for "+Str(n)+" msec.")
      Delay(n): PrintN("Thread #"+Str(ID)+" delivering")
      SignalSemaphore(\Semaphore_Deliver)
    ForEver
  EndWith
EndProcedure

; User IO & init
If OpenConsole()
  Define i, j
  Repeat
    Print("Enter number of workers to use [2-2000]: ")
    j=Val(Input())
  Until j>=2 And j<=2000
  ReDim Comm(j)
  For i=1 To j
    With Comm(i)
      \Semaphore_Release =CreateSemaphore()
      \Semaphore_Joining =CreateSemaphore()
      \Semaphore_Deliver =CreateSemaphore()
      \Semaphore_Leaving =CreateSemaphore()
      \ThreadID = CreateThread(@Worker(),i)
    EndWith
  Next
  PrintN("Work started, "+Str(j)+" workers has been called.")
  CheckPoint()
  Print("Press ENTER to exit"): Input()
EndIf


"""

Based on https://pymotw.com/3/threading/

"""

import threading
import time
import random

def worker(workernum, barrier):
    # task 1
    sleeptime = random.random()
    print('Starting worker '+str(workernum)+" task 1, sleeptime="+str(sleeptime))
    time.sleep(sleeptime)
    print('Exiting worker'+str(workernum))
    barrier.wait()
    # task 2
    sleeptime = random.random()
    print('Starting worker '+str(workernum)+" task 2, sleeptime="+str(sleeptime))
    time.sleep(sleeptime)
    print('Exiting worker'+str(workernum))

barrier = threading.Barrier(3)

w1 = threading.Thread(target=worker, args=((1,barrier)))
w2 = threading.Thread(target=worker, args=((2,barrier)))
w3 = threading.Thread(target=worker, args=((3,barrier)))

w1.start()
w2.start()
w3.start()


#lang racket
(define t 5)     ; total number of threads
(define count 0) ; number of threads arrived at rendezvous
(define mutex      (make-semaphore 1)) ; exclusive access to count
(define turnstile  (make-semaphore 0))
(define turnstile2 (make-semaphore 1))
(define ch (make-channel))

(define (make-producer name start)
  (λ ()
    (let loop ([n start])
      (sleep (* 0.01 (random 10))) ; "compute" something
      ;; rendezvous
      (semaphore-wait mutex)
      (set! count (+ count 1)) ; we have arrived
      (when (= count t) ; are we the last to arrive?
        (semaphore-wait turnstile2)
        (semaphore-post turnstile))
      (semaphore-post mutex)
      ; avoid deadlock problem:
      (semaphore-wait turnstile)
      (semaphore-post turnstile)
      ; critical point
      (channel-put ch n) ; send result to controller
      ; leave properly
      (semaphore-wait mutex)
      (set! count (- count 1))
      (when (= count 0) ; are we the last to leave?
        (semaphore-wait turnstile)
        (semaphore-post turnstile2))
      (semaphore-post mutex)

      (semaphore-wait turnstile2)
      (semaphore-post turnstile2)

      (loop (+ n t)))))

; start t workers:
(map (λ(start) (thread (make-producer start start)))
     (range 0 t))

(let loop ()
  (displayln (for/list ([_ t]) (channel-get ch)))
  (loop))


my $TotalWorkers = 3;
my $BatchToRun = 3;
my @TimeTaken = (5..15); # in seconds

my $batch_progress = 0;
my @batch_lock = map { Semaphore.new(1) } , ^$TotalWorkers;
my $lock = Lock.new;

sub assembly_line ($ID) {
   my $wait;
   for ^$BatchToRun -> $j {
      $wait = @TimeTaken.roll;
      say "Worker ",$ID," at batch $j will work for ",$wait," seconds ..";
      sleep($wait);
      $lock.protect: {
         my $k = ++$batch_progress;
         print "Worker ",$ID," is done and update batch $j complete counter ";
         say "to $k of $TotalWorkers";
         if ($batch_progress == $TotalWorkers) {
            say ">>>>> batch $j completed.";
            $batch_progress = 0; # reset for next batch
            for @batch_lock { .release }; # and ready for next batch
         };
       };

       @batch_lock[$ID].acquire; # for next batch
   }
}

for ^$TotalWorkers -> $i {
   Thread.start(
      sub {
         @batch_lock[$i].acquire;
         assembly_line($i);
      }
   );
}


require 'socket'

# A Workshop runs all of its workers, then collects their results. Use
# Workshop#add to add workers and Workshop#work to run them.
#
# This implementation forks some processes to run the workers in
# parallel. Ruby must provide Kernel#fork and 'socket' library must
# provide UNIXSocket.
#
# Why processes and not threads? C Ruby still has a Global VM Lock,
# where only one thread can hold the lock. One platform, OpenBSD, still
# has userspace threads, with all threads on one cpu core. Multiple
# processes will not compete for a single Global VM Lock and can run
# on multiple cpu cores.
class Workshop
  # Creates a Workshop.
  def initialize
    @sockets = {}
  end

  # Adds a worker to this Workshop. Returns a worker id _wid_ for this
  # worker. The worker is a block that takes some _args_ and returns
  # some value. Workshop#work will run the block.
  #
  # This implementation forks a process for the worker. This process
  # will use Marshal with UNIXSocket to receive the _args_ and to send
  # the return value. The _wid_ is a process id. The worker also
  # inherits _IO_ objects, which might be a problem if the worker holds
  # open a pipe or socket, and the other end never reads EOF.
  def add
    child, parent = UNIXSocket.pair

    wid = fork do
      # I am the child.
      child.close
      @sockets.each_value { |sibling| sibling.close }

      # Prevent that all the children print their backtraces (to a mess
      # of mixed lines) when user presses Control-C.
      Signal.trap("INT") { exit! }

      loop do
        # Wait for a command.
        begin
          command, args = Marshal.load(parent)
        rescue EOFError
          # Parent probably died.
          break
        end

        case command
        when :work
          # Do work. Send result to parent.
          result = yield *args
          Marshal.dump(result, parent)
        when :remove
          break
        else
          fail "bad command from workshop"
        end
      end
    end

    # I am the parent.
    parent.close
    @sockets[wid] = child
    wid
  end

  # Runs all of the workers, and collects the results in a Hash. Passes
  # the same _args_ to each of the workers. Returns a Hash that pairs
  # _wid_ => _result_, where _wid_ is the worker id and _result_ is the
  # return value from the worker.
  #
  # This implementation runs the workers in parallel, and waits until
  # _all_ of the workers finish their results. Workshop provides no way
  # to start the work without waiting for the work to finish. If a
  # worker dies (for example, by raising an Exception), then
  # Workshop#work raises a RuntimeError.
  def work(*args)
    message = [:work, args]
    @sockets.each_pair do |wid, child|
      Marshal.dump(message, child)
    end

    # Checkpoint! Wait for all workers to finish.
    result = {}
    @sockets.each_pair do |wid, child|
      begin
        # This waits until the child finishes a result.
        result[wid] = Marshal.load(child)
      rescue EOFError
        fail "Worker #{wid} died"
      end
    end
    result
  end

  # Removes a worker from the Workshop, who has a worker id _wid_.
  # If there is no such worker, raises ArgumentError.
  #
  # This implementation kills and reaps the process for the worker.
  def remove(wid)
    unless child = @sockets.delete(wid)
      raise ArgumentError, "No worker #{wid}"
    else
      Marshal.dump([:remove, nil], child)
      child.close
      Process.wait(wid)
    end
  end
end

# First create a Workshop.
require 'pp'
shop = Workshop.new
wids = []

# Our workers must not use the same random numbers after the fork.
@fixed_rand = false
def fix_rand
  unless @fixed_rand; srand; @fixed_rand = true; end
end

# Start with some workers.
6.times do
  wids << shop.add do |i|
    # This worker slowly calculates a Fibonacci number.
    fix_rand
    f = proc { |n| if n < 2 then n else f[n - 1] + f[n - 2] end }
    [i, f[25 + rand(10)]]
  end
end

6.times do |i|
  # Do one cycle of work, and print the result.
  pp shop.work(i)

  # Remove a worker.
  victim = rand(wids.length)
  shop.remove wids[victim]
  wids.slice! victim

  # Add another worker.
  wids << shop.add do |j|
    # This worker slowly calculates a number from
    # the sequence 0, 1, 2, 3, 6, 11, 20, 37, 68, 125, ...
    fix_rand
    f = proc { |n| if n < 3 then n else f[n - 1] + f[n - 2] + f[n - 3] end }
    [j, i, f[20 + rand(10)]]
  end
end

# Remove all workers.
wids.each { |wid| shop.remove wid }
pp shop.work(6)


//! We implement this task using Rust's Barriers.  Barriers are simply thread synchronization
//! points--if a task waits at a barrier, it will not continue until the number of tasks for which
//! the variable was initialized are also waiting at the barrier, at which point all of them will
//! stop waiting.  This can be used to allow threads to do asynchronous work and guarantee
//! properties at checkpoints.

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::channel;
use std::sync::{Arc, Barrier};
use std::thread::spawn;

use array_init::array_init;

pub fn checkpoint() {
    const NUM_TASKS: usize = 10;
    const NUM_ITERATIONS: u8 = 10;

    let barrier = Barrier::new(NUM_TASKS);
    let events: [AtomicBool; NUM_TASKS] = array_init(|_| AtomicBool::new(false));

    // Arc for sharing between tasks
    let arc = Arc::new((barrier, events));
    // Channel for communicating when tasks are done
    let (tx, rx) = channel();
    for i in 0..NUM_TASKS {
        let arc = Arc::clone(&arc);
        let tx = tx.clone();
        // Spawn a new worker
        spawn(move || {
            let (ref barrier, ref events) = *arc;
            // Assign an event to this task
            let event = &events[i];
            // Start processing events
            for _ in 0..NUM_ITERATIONS {
                // Between checkpoints 4 and 1, turn this task's event on.
                event.store(true, Ordering::Release);
                // Checkpoint 1
                barrier.wait();
                // Between checkpoints 1 and 2, all events are on.
                assert!(events.iter().all(|e| e.load(Ordering::Acquire)));
                // Checkpoint 2
                barrier.wait();
                // Between checkpoints 2 and 3, turn this task's event off.
                event.store(false, Ordering::Release);
                // Checkpoint 3
                barrier.wait();
                // Between checkpoints 3 and 4, all events are off.
                assert!(events.iter().all(|e| !e.load(Ordering::Acquire)));
                // Checkpoint 4
                barrier.wait();
            }
            // Finish processing events.
            tx.send(()).unwrap();
        });
    }
    drop(tx);
    // The main thread will not exit until all tasks have exited.
    for _ in 0..NUM_TASKS {
        rx.recv().unwrap();
    }
}

fn main() {
    checkpoint();
}


import java.util.{Random, Scanner}

object CheckpointSync extends App {
  val in = new Scanner(System.in)

  /*
   * Informs that workers started working on the task and
   * starts running threads. Prior to proceeding with next
   * task syncs using static Worker.checkpoint() method.
   */
  private def runTasks(nTasks: Int): Unit = {

    for (i <- 0 until nTasks) {
      println("Starting task number " + (i + 1) + ".")
      runThreads()
      Worker.checkpoint()
    }
  }

  /*
   * Creates a thread for each worker and runs it.
   */
  private def runThreads(): Unit =
    for (i <- 0 until Worker.nWorkers) new Thread(new Worker(i + 1)).start()

  class Worker(/* inner class instance variables */ var threadID: Int)
    extends Runnable {
    override def run(): Unit = {
      work()
    }

    /*
     *  Notifies that thread started running for 100 to 1000 msec.
     *  Once finished increments static counter 'nFinished'
     *  that counts number of workers finished their work.
     */
    private def work(): Unit = {
      try {
        val workTime = Worker.rgen.nextInt(900) + 100
        println("Worker " + threadID + " will work for " + workTime + " msec.")
        Thread.sleep(workTime) //work for 'workTime'

        Worker.nFinished += 1 //increases work finished counter

        println("Worker " + threadID + " is ready")
      } catch {
        case e: InterruptedException =>
          System.err.println("Error: thread execution interrupted")
          e.printStackTrace()
      }
    }
  }

  /*
   * Worker inner static class.
   */
  object Worker {
    private val rgen = new Random
    var nWorkers = 0
    private var nFinished = 0

    /*
     * Used to synchronize Worker threads using 'nFinished' static integer.
     * Waits (with step of 10 msec) until 'nFinished' equals to 'nWorkers'.
     * Once they are equal resets 'nFinished' counter.
     */
    def checkpoint(): Unit = {
      while (nFinished != nWorkers)
        try Thread.sleep(10)
        catch {
          case e: InterruptedException =>
            System.err.println("Error: thread execution interrupted")
            e.printStackTrace()
        }
      nFinished = 0
    }
  }

  print("Enter number of workers to use: ")
  Worker.nWorkers = in.nextInt
  print("Enter number of tasks to complete:")
  runTasks(in.nextInt)

}


package require Tcl 8.5
package require Thread

namespace eval checkpoint {
    namespace export {[a-z]*}
    namespace ensemble create
    variable members {}
    variable waiting {}
    variable event
    # Back-end of join operation
    proc Join {id} {
	variable members
	variable counter
	if {$id ni $members} {
	    lappend members $id
	}
	return $id
    }
    # Back-end of leave operation
    proc Leave {id} {
	variable members
	set idx [lsearch -exact $members $id]
	if {$idx > -1} {
	    set members [lreplace $members $idx $idx]
	    variable event
	    if {![info exists event]} {
		set event [after idle ::checkpoint::Release]
	    }
	}
	return
    }
    # Back-end of deliver operation
    proc Deliver {id} {
	variable waiting
	lappend waiting $id

	variable event
	if {![info exists event]} {
	    set event [after idle ::checkpoint::Release]
	}
	return
    }
    # Releasing is done as an "idle" action to prevent deadlocks
    proc Release {} {
	variable members
	variable waiting
	variable event
	unset event
	if {[llength $members] != [llength $waiting]} return
	set w $waiting
	set waiting {}
	foreach id $w {
	    thread::send -async $id {incr ::checkpoint::Delivered}
	}
    }

    # Make a thread and attach it to the public API of the checkpoint
    proc makeThread {{script ""}} {
	set id [thread::create thread::wait]
	thread::send $id {
	    namespace eval checkpoint {
		namespace export {[a-z]*}
		namespace ensemble create

		# Call to actually join the checkpoint group
		proc join {} {
		    variable checkpoint
		    thread::send $checkpoint [list \
			    ::checkpoint::Join [thread::id]]
		}
		# Call to actually leave the checkpoint group
		proc leave {} {
		    variable checkpoint
		    thread::send $checkpoint [list \
			    ::checkpoint::Leave [thread::id]]
		}
		# Call to wait for checkpoint synchronization
		proc deliver {} {
		    variable checkpoint
		    # Do this from within the [vwait] to ensure that we're already waiting
		    after 0 [list thread::send $checkpoint [list \
			    ::checkpoint::Deliver [thread::id]]]
		    vwait ::checkpoint::Delivered
		}
	    }
	}
	thread::send $id [list set ::checkpoint::checkpoint [thread::id]]
	thread::send $id $script
	return $id
    }

    # Utility to help determine whether the checkpoint is in use
    proc anyJoined {} {
	variable members
	expr {[llength $members] > 0}
    }
}


import "random" for Random
import "scheduler" for Scheduler
import "timer" for Timer
import "/ioutil" for Input

var rgen = Random.new()
var nWorkers = 0
var nTasks = 0
var nFinished = 0

var worker = Fn.new { |id|
    var workTime = rgen.int(100, 1000) // 100..999 msec.
    System.print("Worker %(id) will work for %(workTime) msec.")
    Timer.sleep(workTime)
    nFinished = nFinished + 1
    System.print("Worker %(id) is ready.")
}

var checkPoint = Fn.new {
    while (nFinished != nWorkers) {
        Timer.sleep(10)
    }
    nFinished = 0 // reset
}

var runTasks = Fn.new {
    for (i in 1..nTasks) {
        System.print("\nStarting task number %(i).")
        var first = rgen.int(1, nWorkers + 1) // randomize first worker to start
        // schedule other workers to start while another fiber is sleeping
        for (j in 1..nWorkers) {
            if (j != first) Scheduler.add { worker.call(j) }
        }
        worker.call(first) // start first worker
        checkPoint.call()  // start checkPoint
    }
}

nWorkers = Input.integer("Enter number of workers to use: ", 1)
nTasks   = Input.integer("Enter number of tasks to complete: ", 1)
runTasks.call()


const NUM_PARTS=5;  // number of parts used to make the product
var requested=Atomic.Int(-1); // the id of the part the consumer needs
var pipe=Thread.Pipe();       // "conveyor belt" of parts to consumer

fcn producer(id,pipe){
   while(True){ // make part forever
      requested.waitFor(id);  // wait for consumer to ask for my part
      requested.set(-1);      // I'm making the part
      pipe.write(id);         // ship my part
   }
   println(id," stopped");
}

foreach id in (NUM_PARTS){ producer.launch(id,pipe) } // start workers/threads

product:=NUM_PARTS.pump(List(),0);  // parts I have on hand
do(10){	  // make 10 products
   while(False!=(id:=product.filter1n('==(0)))){ // gather parts to make product
      requested.set(id);
      part:=pipe.read();  // get requested part
      product[part]+=1; // assemble part into product
   }
   println("product made: ",product);
   foreach n in (NUM_PARTS){ product[n]-=1 } // remove parts from bin
}
println("Done");	// but workers are still waiting


with Ada.Text_IO;          use Ada.Text_IO;
with Interfaces.C_Streams; use Interfaces.C_Streams;

procedure Test_tty is
begin
   if Isatty(Fileno(Stdin)) = 0 then
      Put_Line(Standard_Error, "stdin is not a tty.");
   else
      Put_Line(Standard_Error, "stdin is a tty.");
   end if;
end Test_tty;


#include <unistd.h>	//for isatty()
#include <stdio.h>	//for fileno()

int main(void)
{
	puts(isatty(fileno(stdin))
		? "stdin is tty"
		: "stdin is not tty");
	return 0;
}


      *>
      *> istty, check id fd 0 is a tty
      *> Tectonics: cobc -xj istty.cob
      *>            echo "test" | ./istty
      *>
       identification division.
       program-id. istty.

       data division.
       working-storage section.
       01 rc usage binary-long.

       procedure division.
       sample-main.

       call "isatty" using by value 0 returning rc
       display "fd 0 tty: " rc

       call "isatty" using by value 1 returning rc
       display "fd 1 tty: " rc upon syserr

       call "isatty" using by value 2 returning rc
       display "fd 2 tty: " rc

       goback.
       end program istty.


(with-open-stream (s *standard-input*)
  (format T "stdin is~:[ not~;~] a terminal~%"
          (interactive-stream-p s)))


File.new("testfile").tty?   #=> false
File.new("/dev/tty").tty?   #=> true
STDIN.tty?  #=> true


import std.stdio;

extern(C) int isatty(int);

void main() {
    if (isatty(0))
        writeln("Input comes from tty.");
    else
        writeln("Input doesn't come from tty.");
}


Open Cons For Input As #1
' Open Cons abre los flujos de entrada (stdin) o salida (stdout) estándar
' de la consola para leer o escribir.

If Err Then
    Print "Input doesn't come from tt."
Else
    Print "Input comes from tty."
End If
Close #1
Sleep


package main

import (
    "golang.org/x/crypto/ssh/terminal"
    "fmt"
    "os"
)

func main() {
    if terminal.IsTerminal(int(os.Stdin.Fd())) {
        fmt.Println("Hello terminal")
    } else {
        fmt.Println("Who are you?  You're not a terminal.")
    }
}


module Main (main) where

import           System.Posix.IO (stdInput)
import           System.Posix.Terminal (queryTerminal)

main :: IO ()
main = do
    isTTY <- queryTerminal stdInput
    putStrLn $ if isTTY
                then "stdin is TTY"
                else "stdin is not TTY"


/* Check input device is a terminal, in Jsish */
;Interp.conf().subOpts.istty;

/*
=!EXPECTSTART!=
Interp.conf().subOpts.istty ==> false
=!EXPECTEND!=
*/


if isa(STDIN, Base.TTY)
    println("This program sees STDIN as a TTY.")
else
    println("This program does not see STDIN as a TTY.")
end


// Kotlin Native version 0.5

import platform.posix.*

fun main(args: Array<String>) {
    if (isatty(STDIN_FILENO) != 0)
        println("stdin is a terminal")
    else
        println("stdin is not a terminal")
}


def isTerm = System.Console.IsInputRedirected;


import terminal

echo if stdin.isatty: "stdin is a terminal" else: "stdin is not a terminal"


let () =
  print_endline (
    if Unix.isatty Unix.stdin
    then "Input comes from tty."
    else "Input doesn't come from tty."
  )


(define (isatty? fd) (syscall 16 fd 19))
(print (if (isatty? stdin)
   "Input comes from tty."
   "Input doesn't come from tty."))


use strict;
use warnings;
use 5.010;
if (-t) {
    say "Input comes from tty.";
}
else {
    say "Input doesn't come from tty.";
}


without js -- (no input redirection in a browser!)
printf(1,"stdin:%t, stdout:%t, stderr:%t\n",{isatty(0),isatty(1),isatty(2)})


void main()
{
    if(Stdio.Terminfo.is_tty())
	write("Input comes from tty.\n");
    else
        write("Input doesn't come from tty.\n");
}


from sys import stdin
if stdin.isatty():
    print("Input comes from tty.")
else:
    print("Input doesn't come from tty.")


  [ $ |from sys import stdin
to_stack( 1 if stdin.isatty() else 0)|
    python ]                            is ttyin ( --> b )

  ttyin if
    [ say "Looks like a teletype." ]
  else
    [ say "Not a teletype." ]


say $*IN.t ?? "Input comes from tty." !! "Input doesn't come from tty.";


/*REXX program determines if input comes from terminal or standard input*/

if queued()  then say 'input comes from the terminal.'
             else say 'input comes from the (stacked) terminal queue.'

                                       /*stick a fork in it, we're done.*/


# Project  : Check input device is a terminal

load "stdlib.ring"

if isWindows()
   write("mycmd.bat","
   @echo off
    timeout 1 2>nul >nul
    if errorlevel 1 (
       echo input redirected
        ) else (
       echo input is console
       )
       ")
    see SystemCmd("mycmd.bat")
ok


File.new("testfile").isatty   #=> false
File.new("/dev/tty").isatty   #=> true


/* Uses C library interface */

extern crate libc;

fn main() {
    let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
    if istty {
        println!("stdout is tty");
    } else {
        println!("stdout is not tty");
    }
}


import org.fusesource.jansi.internal.CLibrary._

object IsATty  extends App {

  var enabled = true

  def apply(enabled: Boolean): Boolean = {
    // We must be on some unix variant..
    try {
      enabled && isatty(STDIN_FILENO) == 1
    }
    catch {
      case ignore: Throwable =>
        ignore.printStackTrace()
        false

    }
  }

    println("tty " + apply(true))
}


val stdinRefersToTerminal : bool = Posix.ProcEnv.isatty Posix.FileSys.stdin


if {[catch {fconfigure stdin -mode}]} {
    puts "Input doesn't come from tty."
} else {
    puts "Input comes from tty."
}


#!/bin/sh

if [ -t 0 ]
then
   echo "Input is a terminal"
else
   echo "Input is NOT a terminal"
fi


import "io" for Stdin

System.print("Input device is a terminal? %(Stdin.isTerminal ? "Yes" : "No")")


const S_IFCHR=0x2000;
fcn S_ISCHR(f){ f.info()[4].bitAnd(S_IFCHR).toBool() }
S_ISCHR(File.stdin).println();


#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>

typedef unsigned long long int u64;

#define TRUE 1
#define FALSE 0

int primality_pretest(u64 k) {
    if (!(k %  3) || !(k %  5) || !(k %  7) || !(k % 11) || !(k % 13) || !(k % 17) || !(k % 19) || !(k % 23)) return (k <= 23);
    return TRUE;
}

int probprime(u64 k, mpz_t n) {
    mpz_set_ui(n, k);
    return mpz_probab_prime_p(n, 0);
}

int is_chernick(int n, u64 m, mpz_t z) {
    u64 t = 9 * m;
    if (primality_pretest(6 * m + 1) == FALSE) return FALSE;
    if (primality_pretest(12 * m + 1) == FALSE) return FALSE;
    for (int i = 1; i <= n - 2; i++) if (primality_pretest((t << i) + 1) == FALSE) return FALSE;
    if (probprime(6 * m + 1, z) == FALSE) return FALSE;
    if (probprime(12 * m + 1, z) == FALSE) return FALSE;
    for (int i = 1; i <= n - 2; i++) if (probprime((t << i) + 1, z) == FALSE) return FALSE;
    return TRUE;
}

int main(int argc, char const *argv[]) {
    mpz_t z;
    mpz_inits(z, NULL);

    for (int n = 3; n <= 10; n ++) {
        u64 multiplier = (n > 4) ? (1 << (n - 4)) : 1;

        if (n > 5) multiplier *= 5;

        for (u64 k = 1; ; k++) {
            u64 m = k * multiplier;

            if (is_chernick(n, m, z) == TRUE) {
                printf("a(%d) has m = %llu\n", n, m);
                break;
            }
        }
    }

    return 0;
}


#include <gmp.h>
#include <iostream>

using namespace std;

typedef unsigned long long int u64;

bool primality_pretest(u64 k) {     // for k > 23

    if (!(k %  3) || !(k %  5) || !(k %  7) || !(k % 11) ||
        !(k % 13) || !(k % 17) || !(k % 19) || !(k % 23)
    ) {
        return (k <= 23);
    }

    return true;
}

bool probprime(u64 k, mpz_t n) {
    mpz_set_ui(n, k);
    return mpz_probab_prime_p(n, 0);
}

bool is_chernick(int n, u64 m, mpz_t z) {

    if (!primality_pretest(6 * m + 1)) {
        return false;
    }

    if (!primality_pretest(12 * m + 1)) {
        return false;
    }

    u64 t = 9 * m;

    for (int i = 1; i <= n - 2; i++) {
        if (!primality_pretest((t << i) + 1)) {
            return false;
        }
    }

    if (!probprime(6 * m + 1, z)) {
        return false;
    }

    if (!probprime(12 * m + 1, z)) {
        return false;
    }

    for (int i = 1; i <= n - 2; i++) {
        if (!probprime((t << i) + 1, z)) {
            return false;
        }
    }

    return true;
}

int main() {

    mpz_t z;
    mpz_inits(z, NULL);

    for (int n = 3; n <= 10; n++) {

        // `m` is a multiple of 2^(n-4), for n > 4
        u64 multiplier = (n > 4) ? (1 << (n - 4)) : 1;

        // For n > 5, m is also a multiple of 5
        if (n > 5) {
            multiplier *= 5;
        }

        for (u64 k = 1; ; k++) {

            u64 m = k * multiplier;

            if (is_chernick(n, m, z)) {
                cout << "a(" << n << ") has m = " << m << endl;
                break;
            }
        }
    }

    return 0;
}


T Date
   String month
   Int day
   F (month, day)
      .month = month
      .day = day

V dates = [Date(‘May’, 15), Date(‘May’, 16), Date(‘May’, 19), Date(‘June’, 17), Date(‘June’, 18),
           Date(‘July’, 14), Date(‘July’, 16), Date(‘August’, 14), Date(‘August’, 15), Date(‘August’, 17)]

DefaultDict[Int, Set[String]] monthTable
L(date) dates
   monthTable[date.day].add(date.month)

DefaultDict[String, Set[Int]] dayTable
L(date) dates
   dayTable[date.month].add(date.day)

Set[String] possibleMonths
Set[Int] possibleDays

L(month, days) dayTable
   I days.len > 1
      possibleMonths.add(month)

L(month, days) dayTable
   L(day) days
      I monthTable[day].len == 1
         possibleMonths.remove(month)
print(‘After first Albert's sentence, possible months are ’Array(possibleMonths).join(‘, ’)‘.’)

L(day, months) monthTable
   I months.len > 1
      possibleDays.add(day)

Set[Int] impossibleDays
L(day) possibleDays
   I monthTable[day].intersection(possibleMonths).len > 1
      impossibleDays.add(day)
L(day) impossibleDays
   possibleDays.remove(day)
print(‘After Bernard's sentence, possible days are ’Array(possibleDays).join(‘, ’)‘.’)

Set[String] impossibleMonths
L(month) possibleMonths
   I dayTable[month].intersection(possibleDays).len > 1
      impossibleMonths.add(month)
L(month) impossibleMonths
   possibleMonths.remove(month)

assert(possibleMonths.len == 1)
V month = possibleMonths.pop()
print(‘After second Albert's sentence, remaining month is ’month‘...’)

possibleDays = possibleDays.intersection(dayTable[month])
assert(possibleDays.len == 1)
V day = possibleDays.pop()
print(‘and thus remaining day is ’day‘.’)

print()
print(‘So birthday date is ’month‘ ’day‘.’)


// Generate Chernick's Carmichael numbers. Nigel Galloway: June 1st., 2019
let fMk m k=isPrime(6*m+1) && isPrime(12*m+1) && [1..k-2]|>List.forall(fun n->isPrime(9*(pown 2 n)*m+1))
let fX k=Seq.initInfinite(fun n->(n+1)*(pown 2 (k-4))) |> Seq.filter(fun n->fMk n k )
let cherCar k=let m=Seq.head(fX k) in printfn "m=%d primes -> %A " m ([6*m+1;12*m+1]@List.init(k-2)(fun n->9*(pown 2 (n+1))*m+1))
[4..9] |> Seq.iter cherCar


#include "isprime.bas"

Function PrimalityPretest(k As Integer) As Boolean
    Dim As Integer ppp(1 To 8) = {3,5,7,11,13,17,19,23}
    For i As Integer = 1 To Ubound(ppp)
        If k Mod ppp(i) = 0 Then Return (k <= 23)
    Next i
    Return True
End Function

Function isChernick(n As Integer, m As Integer) As Boolean
    Dim As Integer i, t = 9 * m

    If Not PrimalityPretest(6 * m + 1) Then Return False
    If Not PrimalityPretest(12 * m + 1) Then Return False

    For i = 1 To n-1
        If Not PrimalityPretest(t * (2 ^ i) + 1) Then Return False
    Next i

    If Not isPrime(6 * m + 1) Then Return False
    If Not isPrime(12 * m + 1) Then Return False

    For i = 1 To n - 2
        If Not isPrime(t * (2 ^ i) + 1) Then Return False
    Next i
    Return True
End Function

Dim As Uinteger multiplier, k, m = 1
For n As Integer = 3 To 9
    multiplier = Iif (n > 4, 2 ^ (n-4), 1)
    If n > 5 Then multiplier *= 5

    k = 1
    Do
        m = k * multiplier
        If isChernick(n, m) Then
            Print "a(" & n & ") has m = " & m
            Exit Do
        End If
        k += 1
    Loop
Next n
Sleep


with Ada.Text_IO; use Ada.Text_IO;

procedure Main is
   type Months is
     (January, February, March, April, May, June, July, August, September,
      November, December);
   type day_num is range 1 .. 31;
   type birthdate is record
      Month  : Months;
      Day    : day_num;
      Active : Boolean;
   end record;

   type birthday_list is array (Positive range <>) of birthdate;

   Possible_birthdates : birthday_list :=
     ((May, 15, True), (May, 16, True), (May, 19, True), (June, 17, True),
      (June, 18, True), (July, 14, True), (July, 16, True), (August, 14, True),
      (August, 15, True), (August, 17, True));

   procedure print_answer is
   begin
      for the_day of Possible_birthdates loop
         if the_day.Active then
            Put_Line (the_day.Month'Image & "," & the_day.Day'Image);
         end if;
      end loop;
   end print_answer;

   procedure print_remaining is
      count : Natural := 0;
   begin
      for date of Possible_birthdates loop
         if date.Active then
            count := count + 1;
         end if;
      end loop;
      Put_Line (count'Image & " remaining.");
   end print_remaining;

   -- the month cannot have a unique day
   procedure first_pass is
      count : Natural;
   begin
      for first_day of Possible_birthdates loop
         count := 0;
         for next_day of Possible_birthdates loop
            if first_day.Day = next_day.Day then
               count := count + 1;
            end if;
         end loop;

         if count = 1 then
            for the_day of Possible_birthdates loop
               if the_day.Active and then first_day.Month = the_day.Month then
                  the_day.Active := False;
               end if;
            end loop;
         end if;
      end loop;
   end first_pass;

   -- the day must now be unique
   procedure second_pass is
      count : Natural;
   begin
      for first_day of Possible_birthdates loop
         if first_day.Active then
            count := 0;
            for next_day of Possible_birthdates loop
               if next_day.Active then
                  if next_day.Day = first_day.Day then
                     count := count + 1;
                  end if;
               end if;
            end loop;

            if count > 1 then
               for next_day of Possible_birthdates loop
                  if next_day.Active and then next_day.Day = first_day.Day then
                     next_day.Active := False;
                  end if;
               end loop;
            end if;
         end if;
      end loop;
   end second_pass;

   -- the month must now be unique
   procedure third_pass is
      count : Natural;
   begin
      for first_day of Possible_birthdates loop
         if first_day.Active then
            count := 0;
            for next_day of Possible_birthdates loop
               if next_day.Active and then next_day.Month = first_day.Month
               then
                  count := count + 1;
               end if;
            end loop;
            if count > 1 then
               for next_day of Possible_birthdates loop
                  if next_day.Active and then next_day.Month = first_day.Month
                  then
                     next_day.Active := False;
                  end if;
               end loop;
            end if;
         end if;
      end loop;
   end third_pass;

begin
   print_remaining;
   first_pass;

   print_remaining;
   second_pass;

   print_remaining;
   third_pass;

   print_answer;
end Main;


package main

import (
    "fmt"
    "math/big"
)

var (
    zero = new(big.Int)
    prod = new(big.Int)
    fact = new(big.Int)
)

func ccFactors(n, m uint64) (*big.Int, bool) {
    prod.SetUint64(6*m + 1)
    if !prod.ProbablyPrime(0) {
        return zero, false
    }
    fact.SetUint64(12*m + 1)
    if !fact.ProbablyPrime(0) { // 100% accurate up to 2 ^ 64
        return zero, false
    }
    prod.Mul(prod, fact)
    for i := uint64(1); i <= n-2; i++ {
        fact.SetUint64((1<<i)*9*m + 1)
        if !fact.ProbablyPrime(0) {
            return zero, false
        }
        prod.Mul(prod, fact)
    }
    return prod, true
}

func ccNumbers(start, end uint64) {
    for n := start; n <= end; n++ {
        m := uint64(1)
        if n > 4 {
            m = 1 << (n - 4)
        }
        for {
            num, ok := ccFactors(n, m)
            if ok {
                fmt.Printf("a(%d) = %d\n", n, num)
                break
            }
            if n <= 4 {
                m++
            } else {
                m += 1 << (n - 4)
            }
        }
    }
}

func main() {
    ccNumbers(3, 9)
}