1

私は自分のスレッドが sigint をキャッチできる場所に到達しようとしています。kill_receivedシングルトン リストが and の同じ名前空間にsignal_handler()ありdo_the_uploads() 、同じメモリ ロケーションが参照されているように見えます。"print kill_received[0]"しかし、C の実行中に C を制御すると、 Ctrl-C を押したために True であるべきときにFalse が出力されていることがわかります。

kill_received = [False]

def signal_handler(signal, frame):
    global kill_received
    kill_received[0] = True
    print "\nYou pressed Ctrl+C!"
    print (
        "Your logs and their locations are:"
        "\n{}\n{}\n{}".format(debug, error, info))
    sys.exit(0)

def do_the_uploads(file_list, file_quantity,
        retry_list, authenticate):
    """The uploading engine"""
    value = raw_input(
        "\nPlease enter how many conncurent "
        "uploads you want at one time(example: 200)> ")
    value = int(value)
    logger.info('{} conncurent uploads will be used.'.format(value))

    confirm = raw_input(
        "\nProceed to upload files? Enter [Y/y] for yes: ").upper()
    if confirm == "Y":
        kill_received = False
        sys.stdout.write("\x1b[2J\x1b[H")
        q = Queue.Queue()

        def worker():
            global kill_received
            while True and not kill_received[0]:
                print kill_received[0]
                item = q.get()
                upload_file(item, file_quantity, retry_list, authenticate)
                q.task_done()

        for i in range(value):
            t = Thread(target=worker)
            t.setDaemon(True)
            t.start()

        for item in file_list:
            q.put(item)

        q.join()
        print "Finished. Cleaning up processes...",
        #Allowing the threads to cleanup
        time.sleep(4)
        print "done."

メインスクリプトから:

from modules.upload_actions import do_the_uploads, retry, signal_handler

if __name__ == '__main__':
    signal.signal(signal.SIGINT, signal_handler)

    retry_list = []
    file_list, authenticate, ticket_number = main()
    file_quantity = FileQuantity(len(file_list))
    do_the_uploads(file_list, file_quantity, 
            retry_list, authenticate)

アップデート:

まだ成功していませんが、構文を次のように変更しました。

   def worker():
        global kill_received
        while not kill_received[0]:
            time.sleep(1)
            print kill_received[0]
            item = q.get()
            upload_file(item, file_quantity, retry_list, authenticate)
            q.task_done()
4

2 に答える 2

3

何が起こっているのかを理解するための鍵は、あなたが行ったコメントです

いいえ。スレッドがすべて完了したら、アップロードする必要があります...ただし、アップロードする必要があるすべてのファイルのスレッド実行中はそうではありません。

そしてこのコード行:

q.join()

おそらく予想に反して、control-C によってキューの待機が停止されることはありません。この呼び出しが返されるまで、control-C は受け入れられません。何が起こっているかというと、すべてのスレッドがジョブを実行してキューを空にしてから、ラインで待機しています。

item = q.get()

最後のスレッド呼び出しの後でのみq.task_done、メイン スレッドが戻り、control-C を処理します。ただし、その時点で、すべてのスレッドがキューからの追加のアイテムを待機してスタックしている (取得されない) ため、ループを終了することはありません。

これよりも多くのことが行われている可能性がありますが、これが問題であるかどうかを確認するには、キューが空になるまでビジー状態で待機してみてください。

while not q.empty():
    time.sleep(0.1)
q.join()

キューが空であることは、最後のアップロードがキューからプルされたことを意味し、完了したことを意味しないため、後で参加する必要があります。

追加できるもう 1 つのことは、スレッドが終了する必要があることを知らせるキューへの項目Noneです。例えば、

    def worker():
        global kill_received
        while True and not kill_received[0]:
            print kill_received[0]
            item = q.get()
            if item is None:
                q.task_done()
                break
            upload_file(item, file_quantity, retry_list, authenticate)
            q.task_done()

    for i in range(value):
        t = Thread(target=worker)
        t.setDaemon(True)
        t.start()

    for item in file_list:
        q.put(item)

    for i in range(value):
        q.put(None)

もちろん、これはNoneアップロードするのに有効な値ではないことを前提としています。これは control-C の問題には役立ちませんが、プログラムが正常に終了したときにスレッドが終了することを確認するのに役立つ場合があります。

一般的なヘルプとして、スレッドを使用してテストする場合、すべてのスレッドのスタック トレースを出力する方法があると便利です。This SO questionは、それを行う方法について説明しています。

于 2013-11-27T22:16:00.063 に答える
2

False が印刷されているのは、それを印刷する機会がないためです。それがすべてあなたのprint kill_received[0]声明に当たる前に、あなたはそれを殺しました。

考えてみてください。おそらく、次のステートメントの実行の間に Ctrl-C を押す可能性がわずかにあります。

while True and not kill_received[0]:

そしてこの声明:

print kill_received[0]

しかし、それはありそうもありません。それ以外のときにスレッドを中断すると、(whileステートメントからの) ループが停止し、何も出力されなくなります。


編集: 行がkill_received = Falseあります: 問題を引き起こしている可能性があります。それはおそらくkill_received[0] = False

于 2013-11-27T21:42:06.657 に答える