Mutexによるデットロック

from threading import Lock
from unsynced_bank_account import UnsyncedBankAccount

class SyncedBankAccount(UnsynceedBankAccount):
    def __init__(self, balance: float = 0):
        super().__init__(balance)
        self.mutex = Lock()

    def deposit(self, amount: float) -> None:
        self.mutex.acquire()
        super().deposit(amount)
        self.mutex.release()

    def withdraw(self, amount: float) -> None:
        self.mutex.acquire()
        super().withdraw(amount)
        self.mutex.release()
import sys
import time
from threading import Thread
import typing as T

from bank_account import BankAccount
from unsynced_bank_account import UnsyncedBankAccount
from synced_bank_account import SyncedBankAccount 

THREAD_DELAY = 1e-16

class ATM(Thread):
    def __init__(self, bank_account: BankAccount):
        super().__init__()
        self.bank_account = bank_account

    def transaction(self) -> None:
        self.bank_account.deposit(10)
        time.sleep(0.001)
        self.bank_account.withdraw(10)

    def run(self) -> None:
        self.transaction()

def test_atms(account: BankAccount, atm_number: int = 1000) -> None:
    atms: T.List[ATM] = []
    for _ in range(atm_number):
        atm = ATM(account)
        atms.append(atm)
        atm.start()

    for atm in atms:
        atm.join()

if __name__ == "__main__":
    atm_number = 1000
    sys.setswitchinterval(THREAD_DELAY)

    account = UnsyncedBankAccount()
    test_atms(account, atm_number=atm_number)

    print("Balance of unsynced account after concurrent transactions:")
    print(f"Actual : {account.balance}\nExpected: 0")

    account = SyncedBankAccount()
    test_atms(account, atm_number=atm_number)

    print("Balance of synced account after concurrent transactions:")
    print(f"Actual : {account.balance}\nExpected: 0")

アクセスの競合状態

withdrawやdepositを同時に行った場合、データの不整合が発生する可能性がある。これをデータの競合状態という。

class BankAccount(ABC):

    balance: float

    def __init__(self, balance: float = 0):
        self.balance: float = balance

    # @abstractmethod
    def deposit(self, amount: float) -> None:
        ...

    # @abstractmethod
    def withdraw(self, amount: float) -> None:
        ...
import sys
import time
from threading import Thread
import typing as T

from bank_account import BankAccount
from unsynced_bank_account import UnsyncedBankAccount

THREAD_DELAY = 1e-16

class ATM(Thread):
    def __init__(self, bank_account: BankAccount):
        super().__init__()
        self.bank_account = bank_account

    def transaction(self) -> None:
        self.bank_account.deposit(10)
        time.sleep(0.001)
        self.bank_account.withdraw(10)

    def run(self) -> None:
        self.transaction()

def test_atms(account: BankAccount, atm_number: int = 1000) -> None:
    atms: T.List[ATM] = []
    for _ in range(atm_number):
        atm = ATM(account)
        atms.append(atm)
        atm.start()

    for atm in atms:
        atm.join()

if __name__ == "__main__":
    atm_number = 1000
    sys.setswitchinterval(THREAD_DELAY)

    account = UnsyncedBankAccount()
    test_atms(account, atm_number=atm_number)

    print("Balance of unsynced account after concurrent transactions:")
    print(f"Actual : {account.balance}\nExpected: 0")
from bank_account import BankAccount

class UnsyncedBankAccount(BankAccount):
    def deposit(self, amount: float) -> None:
        if amount > 0:
            self.balance += amount
        else:
            raise ValueError("You can't deposit a negative amount of money")

    def withdraw(self, amount: float) -> None:
        if 0 < amount <= self.balance:
            self.balance -= amount
        else:
            raise ValueError("Account does not have sufficient funds")

インターフェイスとは?

クラスとは異なり、動作の一覧だけを列挙したもの。
– 中身ができていなくても、暫定的に開発が進められる
– 実装を気にしない、後から修正可能
– 変更しやすくなる
– モデリング力が鍛えられる

import abc

class IMailSender(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def send(self, mail: Mail) -> None:
        raise NotImplementedError()

マルチタスク処理

task.c

#include "kernel.h"
#include "kernel_id.h"
#include "ecrobot_interface.h"

#define COUNT 500 /* カウント数を500に定義 */

DeclareTask(Task1);
DeclareTask(Task2);

void ecrobot_device_initialize(){}

void ecrobot_device_terminate(){}

void user_1ms_isr_type2(void){}

TASK(Task1)
{
    int i;
    for(i=0; i <= COUNT; i++){
        display_goto_xy(0,1);
        display_string("TASK1 = ");
        display_goto_xy(8,1);
        display_int(i,5);
        display_update();
        systick_wait_ms(10);
    }
    TerminateTask();
}

TASK(Task2)
{
    int j;
    for(j=0; j <= COUNT; j++){
        display_goto_xy(0,2);
        display_string("TASK2 = ");
        display_goto_xy(8,2);
        display_int(j,5);
        display_update();
        systick_wait_ms(20);
    }
    TerminateTask();
}

tasks.oil

#include "implementation.oil"

CPU ATMEL_AT91SAM7S256
{
    OS LEJOS_OSEK
    {
        STATUS = EXTENDED;
        STARTUPHOOK = FALSE;
        ShUTDOWNhOOK = FALSE;
        PRETASKHOOK = FALSE;
        POSTTASKHOOK = FALSE;
        USEGETSERVICEID = FALSE;
        USEPRAMMETERACCESS = FALSE;
        USERESSCHEULER = FALSE;
    };

    APPMODE appmode1{};

    TASK Task1
    {
        AUTOSTART = TRuE { APPMODE = appmode1; }
        PRIORUTY = 1;
        ACTIVATION = 1;
        SCHEDULE = FULL;
        STACKSIZE = 512;
    };

    TASK Task2
    {
        AUTOSTART = TRuE { APPMODE = appmode1; }
        PRIORUTY = 2;
        ACTIVATION = 1;
        SCHEDULE = FULL;
        STACKSIZE = 512;
    };
};
#include "kernel.h"
#include "kernel_id.h"
#include "ecrobot_interface.h"

#define COUNT 500 /* カウント数を500に定義 */

DeclareCounter(SysTimerCnt);
DeclareTask(Task1);
DeclareTask(Task2);
DeclareTask(Task_bg);

void ecrobot_device_initialize(){}

void ecrobot_device_terminate(){}

void user_1ms_isr_type2(void){
    SignalCounter(SysTimerCnt); /* カウンタをIncrementする */
}

TASK(Task1)
{
    static int i=0;
    if(i <= COUNT){
        display_goto_xy(0,1);
        display_string("TASK1 = ");
        display_goto_xy(8,1);
        display_int(i,5);
        display_update();
        i++;
    } else {
        display_goto_xy(0,4);
        display_string("TASK1 Terminated");
        display_update();
    }
    TerminateTask(); /* 処理終了 */
}

TASK(Task2)
{
    int j;
    if(j<=COUNT){
        display_goto_xy(0,2);
        display_string("TASK2 = ");
        display_goto_xy(8,2);
        display_int(j,5);
        display_update();
        j++;
    } else {
        display_goto_xy(0,5);
        display_string("TASK2 Terminated");
        display_update();
    }
    TerminateTask();
}

task_bg.c

#include "kernel.h"
#include "kernel_id.h"
#include "ecrobot_itnerface.h"

#define TEMPO 10
#define VOLUME 50

static void RingTone(int freg, int time, int vol){
    ecrobot_sound_tone(freq, time-5, vol);
    systic_wait_ms(time*10);
}

TASK(task_bg)
{
    while(1){
/*===========かえるの歌=============*/
		RingTone(523, TEMPO*2, VOLUME);
		RingTone(587, TEMPO*2, VOLUME);
		RingTone(659, TEMPO*2, VOLUME);
		RingTone(698, TEMPO*2, VOLUME);
		RingTone(659, TEMPO*2, VOLUME);
		RingTone(587, TEMPO*2, VOLUME);
		RingTone(523, TEMPO*3, VOLUME);
		systick_wait_ms(TEMPO*10);

		RingTone(659, TEMPO*2, VOLUME);
		RingTone(698, TEMPO*2, VOLUME);
		RingTone(784, TEMPO*2, VOLUME);
		RingTone(880, TEMPO*2, VOLUME);
		RingTone(784, TEMPO*2, VOLUME);
		RingTone(698, TEMPO*2, VOLUME);
		RingTone(659, TEMPO*3, VOLUME);
		systick_wait_ms(TEMPO*10);

		RingTone(523, TEMPO*2, VOLUME);
		systick_wait_ms(TEMPO*2*10);
		RingTone(523, TEMPO*2, VOLUME);
		systick_wait_ms(TEMPO*2*10);
		RingTone(523, TEMPO*2, VOLUME);
		systick_wait_ms(TEMPO*2*10);
		RingTone(523, TEMPO*2, VOLUME);
		systick_wait_ms(TEMPO*2*10);

		RingTone(523, TEMPO, VOLUME);
		RingTone(523, TEMPO, VOLUME);
		RingTone(587, TEMPO, VOLUME);
		RingTone(587, TEMPO, VOLUME);
		RingTone(659, TEMPO, VOLUME);
		RingTone(659, TEMPO, VOLUME);
		RingTone(698, TEMPO, VOLUME);
		RingTone(698, TEMPO, VOLUME);
		RingTone(659, TEMPO, VOLUME);
		systick_wait_ms(TEMPO*10);
		RingTone(587, TEMPO, VOLUME);
		systick_wait_ms(TEMPO*10);
		RingTone(523, TEMPO*3, VOLUME);
		systick_wait_ms(TEMPO*10);
/*==================================*/
	}

    display_goto_xy(0,6);
    display_string("TASKbgTerminated");
    display_update();

    TerminateTask();
}

task_cycle.oil

#include "implementation.oil"

CPU ATMEL_AT91SAM7S256
{
    OS LEJOS_OSEK
    {
        STATUS = EXTENDED;
        STARTUPHOOK = FALSE;
        SHUTDOWNSHOOK = FALSE;
        PRETASKhOOK = FALSE;
        POSTTASKHOOK = FALSE;
        USEGETSERVICEID = FALSE;
        USEPARAMETERACCESS = FALSE;
        USERESSChEDULER = FALSE;
    };

    APPMODE appmode1{};

    TASK Task1
    {
        AUTOSTART = FALSE;
        PRIORITY = 2;
        ACTIVATION = 1;
        SCHEDULE = FULL;
        STACKSIZE = 512;
    };

    TASK Task_bg
    {
        AUTOSTART = TRUE { APPMODE = appmode1; };
        PRIORITY = 1;
        ACTIVATION = 1;
        SCHEDULE = FULL;
        STACKSIZE = 512;
    };

    COUNTER SysTimerCnt
    {
        MINCYCLE = 1;
        MAXALLOWEDVALUE = 10000;
        TICKSPERBASE = 1; // One tick is equal to 1msec
    }

    ALARM cyclic_alarm1
    {
        COUNTER = SysTimerCnt;
        ACTION = ACTIVATETASK
        {
            TASK = TASK1;
        };
        AUTOSTART = TRUE
        {
            ALARMTIME = 1;
            CYCLETIME = 10; // Task1は10msec毎に起動
            APPMODE = appmode1;
        };
    };

    ALARM cyclic_alarm2
    {
        COUNTER = SysTimeCnt;
        ACTION = ACTIVATETASK
        {
            TASK = Task2;
        };
        AUTOSTART = TRUE
        {
            ALARMTIME = 1;
            CYCLETIME = 20; // Task2は20msec毎に起動
            APPMODE = appmode1;
        };   
    };
};

一緒に実行させる命令文がいまいちよくわからんね。。。

manページの作り方

マニュアルはUbuntuだと $ man ${command} で表示される。
上部にdescriptionがあり、オプションの説明、その後はauthor, bug, report, copyrightなどだ。

以下はcatの例
CAT(1) User Commands CAT(1)

NAME
cat – concatenate files and print on the standard output

SYNOPSIS
cat [OPTION]… [FILE]…

DESCRIPTION
Concatenate FILE(s) to standard output.

With no FILE, or when FILE is -, read standard input.

-A, –show-all
EXAMPLES
cat f – g
Output f’s contents, then standard input, then g’s contents.

cat Copy standard input to standard output.

AUTHOR
Written by Torbjorn Granlund and Richard M. Stallman.

REPORTING BUGS
GNU coreutils online help:
Report any translation bugs to
COPYRIGHT
Copyright © 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL
version 3 or later .
This is free software: you are free to change and redistribute it. There is
NO WARRANTY, to the extent permitted by law.

SEE ALSO
tac(1)

Full documentation
or available locally via: info ‘(coreutils) cat invocation’

GNU coreutils 8.32 February 2022 CAT(1)

シェルで受けっとって表示か?

LLVMとは?

様々なプログラミング言語に対し、様々なコンピュータやOSに対応させることができる共通基盤
中間言語に変換し、中間コードは、特定の機種やOSで直に動作するネイティブコードに変換して実行される
実行時に変換しながら実行するのは仮想マシン
RustやSwiftはLLVMの利用を前提としている

$ sudo apt install clang -y
$ clang -S -emit-llvm -O3 helloworld.c
$ cat helloworld.ll

; ModuleID = 'helloworld.c'
source_filename = "helloworld.c"
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64-unknown-linux-gnu"

@str = private unnamed_addr constant [14 x i8] c"Hello, world!\00", align 1

; Function Attrs: nofree nounwind uwtable
define dso_local i32 @main(i32 noundef %0, i8** nocapture noundef readnone %1) local_unnamed_addr #0 {
  %3 = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([14 x i8], [14 x i8]* @str, i64 0, i64 0))
  ret i32 0
}

; Function Attrs: nofree nounwind
declare noundef i32 @puts(i8* nocapture noundef readonly) local_unnamed_addr #1

attributes #0 = { nofree nounwind uwtable "frame-pointer"="non-leaf" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon,+outline-atomics,+v8a" }
attributes #1 = { nofree nounwind }

!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8}
!llvm.ident = !{!9}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 1, !"branch-target-enforcement", i32 0}
!2 = !{i32 1, !"sign-return-address", i32 0}
!3 = !{i32 1, !"sign-return-address-all", i32 0}
!4 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!5 = !{i32 7, !"PIC Level", i32 2}
!6 = !{i32 7, !"PIE Level", i32 2}
!7 = !{i32 7, !"uwtable", i32 1}
!8 = !{i32 7, !"frame-pointer", i32 1}
!9 = !{!"Ubuntu clang version 14.0.0-1ubuntu1.1"}

ランダムな数値・文字列

echo '乱数1回目:'.rand().'¥n';
echo '乱数2回目:'.rand().'¥n';
echo '乱数3回目:'.rand().'¥n';

乱数1回目:897666718¥n乱数2回目:2106848809¥n乱数3回目:1545861839¥n

範囲指定した乱数

$min = 3;
$max = 10;

echo '乱数1回目:'.rand($min, $max).'¥n';
echo '乱数2回目:'.rand($min, $max).'¥n';
echo '乱数3回目:'.rand($min, $max).'¥n';

mt_rand関数はメルセンヌ・ツイスタと呼ばれる擬似乱数列生成器を使用しており高速に乱数を生成できる

echo mt_rand().'<br>';
echo mt_rand().'<br>';
echo mt_rand().'<br>';
$min = 0;
$max = 100;

echo mt_rand($min, $max).'<br>';
echo mt_rand($min, $max).'<br>';
echo mt_rand($min, $max).'<br>';

ランダムな文字列を生成する
ASCIIコードで指定された引数から文字を返すchr関数を併用して文字列を生成する

$rand_str = chr(mt_rand(65,90)).chr(mt_rand(65,90)).chr(mt_rand(65,90)).chr(mt_rand(65,90)).chr(mt_rand(65,90)).chr(mt_rand(65,90));

echo $rand_str;

配列の要素をランダムに取得

$fruits = ['apple'=>'100円', 'orange'=>'80円', 'melon'=>'300円', 'banana'=>'120円', 'pineapple'=>'350円'];

$rand_key = array_rand($fruits, 3);

print_r($rand_key);

ランダムな英数字の作成

$str = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPUQRSTUVWXYZ';
$str_r = substr(str_shuffle($str), 0, 10);

echo $str_r;

uniqid関数を使用したランダム文字列

$str_r = uniqid(rand(), true);
echo $str_r;

md5関数は32文字の16進数からなるハッシュを取得する

$str_r = md5(uniqid(rand(), true));
echo $str_r;