0

バックグラウンド

Raspberry Pi Stackexchangeの問題の解決策をコーディングしようとしています。その人はキオスクを作成していて、ネットワークが切断されてから再接続された場合に、Midori (Raspbian Wheezy のブラウザー) が自分自身をリロードすることを望んでいます。インターネット接続を確認するために、プログラムに Google への接続を試行させることにしました。up接続の状態に応じて 0 (ダウン) または 1 (アップ) に割り当てられる変数を使用します。

up新しい再割り当てされた変数をスレッドに送信する際に問題が発生しています。スレッドから「アップは再割り当てされていません」という永続的なストリームを取得しています。

コード

up = -1 #Undefined state

test_net = ("www.google.com", 80)

#Import modules
import subprocess as sub
from time import sleep
import socket
import threading

def reloader(up):
    print "A new thread is born." #Debug
    while True:
        if up == 1:
            print "The system is up."
        elif up == 0:
            print "The system is down."
            #sub.call(["midori", "-e", "Reload"])
        else:
            print "Up has not been reassigned."
        sleep(5)



#Check if internet is up

threading.Thread(target = reloader, args = (up,)).start()

while True:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        s.connect(test_net)
        up = 1
        print up
    except socket.error:
        up = 0
        print up
    s.close()
    sleep(10)
4

1 に答える 1

0

ここでの問題は、引数が Python の関数に渡される方法の誤解です。あなたがそうするとき、あなたはそれを期待しています

up = 1

また

up = 0

グローバル スコープ内から、変数を引数として渡したので、関数はそのスコープ内の変数にreloader反映された変更を確認します。upそれはそれがどのように機能するかではありません。

グローバル スコープ内の名前が引数として指すオブジェクトをreloader関数に渡し、グローバル スコープ内のその名前に新しいオブジェクトを割り当てました。スコープ内の名前は、最初に渡されたオブジェクト ( integer ) を引き続き指しています。upupreloader-1

必要な動作を得るには、次の 2 つのオプションがあります。

1. 引数を渡すのではなく、クロージャーによって状態を共有する

コードに次の 2 つの変更を加えると、すべてが期待どおりに機能します。

  • def reloader(up):と置き換えますdef reloader():
  • threading.Thread(target = reloader, args = (up,)).start()と置き換えますthreading.Thread(target = reloader, args = ()).start()

なんで?Python の関数は、親スコープで定義されたすべての名前を参照できるためです。reloaderという名前の引数を取る必要があるとき、内部でupローカル変数を定義していたため、親スコープで同じ名前の変数を隠していました。しかし、単純に引数を削除すると、 内から読み込もうとすると、Python はそのようなローカル変数がないことを認識し、代わりに親スコープを調べます。したがって、外側のスコープでのへの割り当ては内で表示されます。upreloaderupreloaderupreloader

また

2. 引数として渡されたオブジェクトを変更して状態を共有する

に整数-1reloader引数として渡す代わりに、 を含む変更可能なオブジェクトを渡し、 -1現在新しいオブジェクトを に割り当てている場所でオブジェクトを変更しますup。ときどき提案されるハックの 1 つ (通常、関数内の変数への代入を外側のスコープから見えるようにしたい場合。通常、逆の問題があり、スレッドを使用している場合にのみ発生する可能性があります)。は、変数をリストでラップすることです (つまり、の代わりに初期化upし、その後、関数に引数として渡すときは常にexceptの代わりに参照します)、これはこの場合に機能します。[-1]-1up[0]up

別の方法として、ミュータブル オブジェクト ベースのあまり見苦しくない解決策は、まさにこの目的のために存在するValuemultiprocessing モジュールのクラスを使用することです。(クロージャーによるプロセス間の状態共有は、スレッドの場合のようには不可能であり、マルチプロセッシングを使用する場合、可変オブジェクトを使用して状態を共有する必要性がはるかに高くなることに注意してください。おそらくそれが、マルチプロセッシング モジュールにValueクラスがあり、スレッド モジュールにはクラスがある理由です。私が知る限り、似たようなものはありません。)

このアプローチを使用した作業コードは次のようになります。

test_net = ("www.google.com", 80)

#Import modules
import subprocess as sub
from time import sleep
import socket
import threading
from multiprocessing import Value

up = Value('i', -1) #Undefined state

def reloader(up):
    print "A new thread is born." #Debug
    while True:
        if up.value == 1:
            print "The system is up."
        elif up.value == 0:
            print "The system is down."
            #sub.call(["midori", "-e", "Reload"])
        else:
            print "Up has not been reassigned."
        sleep(5)



#Check if internet is up

threading.Thread(target = reloader, args = (up,)).start()

while True:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        s.connect(test_net)
        up.value = 1
        print up
    except socket.error:
        up.value = 0
        print up
    s.close()
    sleep(10)
于 2013-04-13T22:29:57.660 に答える