在我的GUI代码中,我尝试通过单击一个按钮同时运行loop1和loop2。因此,我使用Thread
来实现这一目标。但我也尝试通过点击另一个按钮来阻止它,但我失败了。在stackoverflow上搜索后,我发现没有直接杀死Thread
的方法。这是代码的一部分:
def loop1():
while True:
call (["raspivid -n -op 150 -w 640 -h 480 -b 2666666.67 -t 5000 -o test.mp4"],shell=True)
call (["raspivid -n -op 150 -w 640 -h 480 -b 2666666.67 -t 5000 -o test1.mp4"],shell=True)
def loop2():
while True:
call (["arecord -D plughw:1 --duration=5 -f cd -vv rectest.wav"],shell=True)
call (["arecord -D plughw:1 --duration=5 -f cd -vv rectest1.wav"],shell=True)
def combine():
Thread(target = loop1).start()
Thread(target = loop2).start()
def stop():
Thread(target = loop1).terminate()
Thread(target = loop2).terminate()
我尝试使用这两个按钮来控制它。
btn1 = Button(tk, text="Start Recording", width=16, height=5, command=combine)
btn1.grid(row=2,column=0)
btn2 = Button(tk, text="Stop Recording", width=16, height=5, command=stop)
btn2.grid(row=3,column=0)
我希望loop1和loop2可以停止button2。显然terminate
中没有Thread
。所以我使用了另一种方法Process
。这是代码:
from subprocess import call
from multiprocessing import Process
def loop1():
while True:
call (["raspivid -n -op 150 -w 640 -h 480 -b 2666666.67 -t 5000 -o test.mp4"],shell=True)
call (["raspivid -n -op 150 -w 640 -h 480 -b 2666666.67 -t 5000 -o test1.mp4"],shell=True)
def loop2():
while True:
call (["arecord -D plughw:1 --duration=5 -f cd -vv rectest.wav"],shell=True)
call (["arecord -D plughw:1 --duration=5 -f cd -vv rectest1.wav"],shell=True)
if __name__ == '__main__':
Process(target = loop1).start()
Process(target = loop2).start()
但是这个程序在我运行后立即完成。我知道terminate
中有Process
个函数。但我不知道如何使用它。
答案 0 :(得分:3)
潜在的解决方案将使用Event
。此外,制作GUI时的一个好的经验法则是使用对象。
from threading import Thread,Event
from subprocess import call
class Controller(object):
def __init__(self):
self.thread1 = None
self.thread2 = None
self.stop_threads = Event()
def loop1(self):
while not self.stop_threads.is_set():
call (["raspivid -n -op 150 -w 640 -h 480 -b 2666666.67 -t 5000 -o test.mp4"],shell=True)
call (["raspivid -n -op 150 -w 640 -h 480 -b 2666666.67 -t 5000 -o test1.mp4"],shell=True)
def loop2(self):
while not self.stop_threads.is_set():
call (["arecord -D plughw:1 --duration=5 -f cd -vv rectest.wav"],shell=True)
call (["arecord -D plughw:1 --duration=5 -f cd -vv rectest1.wav"],shell=True)
def combine(self):
self.stop_threads.clear()
self.thread1 = Thread(target = self.loop1)
self.thread2 = Thread(target = self.loop2)
self.thread1.start()
self.thread2.start()
def stop(self):
self.stop_threads.set()
self.thread1.join()
self.thread2.join()
self.thread1 = None
self.thread2 = None
这样你的按钮调用就会变成:
control = Controller()
btn1 = Button(tk, text="Start Recording", width=16, height=5, command=control.combine)
btn1.grid(row=2,column=0)
btn2 = Button(tk, text="Stop Recording", width=16, height=5, command=control.stop)
btn2.grid(row=3,column=0)
答案 1 :(得分:0)
在启动其他线程之前创建一个threading.Event
对象。我们将其命名为stop
。
在线程函数的while
循环中,测试not stop.is_set()
。
在停止按钮的事件处理程序中,调用stop.set()
。
但是因为你只是在启动其他进程,所以你并不真正需要线程。您可以使用subprocess.Popen
个对象来开始录制过程。
下面,作为一个示例,如何执行此操作,是一个使用多个子进程并行转换大量视频的脚本。在您的情况下,由于您使用的是GUI工具包,因此可以使用计时器定期调用manageprocs()
函数。
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
#
# Author: R.F. Smith <rsmith@xs4all.nl>
# $Date: 2014-02-15 14:44:31 +0100 $
#
# To the extent possible under law, Roland Smith has waived all copyright and
# related or neighboring rights to vid2mkv.py. This work is published from the
# Netherlands. See http://creativecommons.org/publicdomain/zero/1.0/
"""Convert all video files given on the command line to Theora/Vorbis streams
in a Matroska container."""
from __future__ import print_function, division
__version__ = '$Revision: a42ef58 $'[11:-2]
import os
import sys
import subprocess
from multiprocessing import cpu_count
from time import sleep
def warn(s):
"""Print a warning message.
:param s: Message string
"""
s = ' '.join(['Warning:', s])
print(s, file=sys.stderr)
def checkfor(args, rv=0):
"""Make sure that a program necessary for using this script is
available.
:param args: String or list of strings of commands. A single string may
not contain spaces.
:param rv: Expected return value from evoking the command.
"""
if isinstance(args, str):
if ' ' in args:
raise ValueError('no spaces in single command allowed')
args = [args]
try:
with open(os.devnull, 'w') as bb:
rc = subprocess.call(args, stdout=bb, stderr=bb)
if rc != rv:
raise OSError
except OSError as oops:
outs = "Required program '{}' not found: {}."
print(outs.format(args[0], oops.strerror))
sys.exit(1)
def startencoder(fname):
"""Use ffmpeg to convert a video file to Theora/Vorbis
streams in a Matroska container.
:param fname: Name of the file to convert.
:returns: a 3-tuple of a Process, input path and output path
"""
basename, ext = os.path.splitext(fname)
known = ['.mp4', '.avi', '.wmv', '.flv', '.mpg', '.mpeg', '.mov', '.ogv']
if ext.lower() not in known:
warn("File {} has unknown extension, ignoring it.".format(fname))
return (None, fname, None)
ofn = basename + '.mkv'
args = ['ffmpeg', '-i', fname, '-c:v', 'libtheora', '-q:v', '6', '-c:a',
'libvorbis', '-q:a', '3', '-sn', ofn]
with open(os.devnull, 'w') as bitbucket:
try:
p = subprocess.Popen(args, stdout=bitbucket, stderr=bitbucket)
print("Conversion of {} to {} started.".format(fname, ofn))
except:
warn("Starting conversion of {} failed.".format(fname))
return (p, fname, ofn)
def manageprocs(proclist):
"""Check a list of subprocesses tuples for processes that have ended and
remove them from the list.
:param proclist: a list of (process, input filename, output filename)
tuples.
"""
print('# of conversions running: {}\r'.format(len(proclist)), end='')
sys.stdout.flush()
for p in proclist:
pr, ifn, ofn = p
if pr is None:
proclist.remove(p)
elif pr.poll() is not None:
print('Conversion of {} to {} finished.'.format(ifn, ofn))
proclist.remove(p)
sleep(0.5)
def main(argv):
"""Main program.
:param argv: command line arguments
"""
if len(argv) == 1:
binary = os.path.basename(argv[0])
print("{} version {}".format(binary, __version__), file=sys.stderr)
print("Usage: {} [file ...]".format(binary), file=sys.stderr)
sys.exit(0)
checkfor(['ffmpeg', '-version'])
avis = argv[1:]
procs = []
maxprocs = cpu_count()
for ifile in avis:
while len(procs) == maxprocs:
manageprocs(procs)
procs.append(startencoder(ifile))
while len(procs) > 0:
manageprocs(procs)
if __name__ == '__main__':
main(sys.argv)