-1

i have a program that uses gdal to process pictures. That is done in a thread that is started with a button click. Now, i need a way to terminate this thread at any given point, also with a button click. So i defined a function that i call when the button is clicked:

def terminateThread(self):
   self.change_button_caption.emit('Start')
   self.print_log.emit('Vorgang abgebrochen')
   self.show_progress.emit(0)
   self.terminate()

When i replace the actual code with a sleep order, this works. But it doesn't when the thread called a gdal function. How can i achieve the termination of this thread at any time?

this is the thread:

class MapThread(QThread):
    print_log = Signal(str)
    show_progress = Signal(int)
    change_button_caption = Signal(str)

    def __init__(self, path, tab_filelist, targetpath):
        QThread.__init__(self)
        self.path = path
        self.tab_filelist = tab_filelist
        self.targetpath = targetpath

    def run(self):
        self.change_button_caption.emit('Stop')
        print('MapThread run', flush=True)
        # try:
        from osgeo import gdal
        from osgeo import osr
        self.show_progress.emit(0)

        filename = self.tab_filelist[0].rsplit('\\', 1)[1].rsplit('.', 1)[0]
        path2 = self.targetpath + "\\" + filename + ".vrt"
        pathout = self.targetpath + "\\" + filename + ".mbtiles"

        d = gdal.Open(self.path)
        proj = osr.SpatialReference(wkt=d.GetProjection())
        self.print_log.emit('EPSG Code der Bilddaten: ' + proj.GetAttrValue('AUTHORITY', 1))
        # Vituelles Raster erzeugen
        vrt_options = gdal.BuildVRTOptions(resampleAlg='cubic', outputSRS=proj)
        gdal.BuildVRT(path2, self.tab_filelist, options=vrt_options)

        print('VRT Datei erzeugt', flush=True)
        self.print_log.emit('VRT Datei erzeugt')
        self.show_progress.emit(10)
        # mbtiles generieren
        creation_options = ["TILE_FORMAT=JPEG", "QUALITY=90"]
        
        src_ds = gdal.Open(path2)
        gdal.Translate(pathout, src_ds, format='mbtiles', creationOptions=creation_options)
        print('MB Tiles generiert', flush=True)
        self.print_log.emit('MB Tiles generiert')
        self.show_progress.emit(75)
        # Overviews erzeugen
        Image = gdal.Open(pathout, 1)
        gdal.SetConfigOption("COMPRESS_OVERVIEW", "DEFLATE")
        Image.BuildOverviews("AVERAGE", [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048])
        self.show_progress.emit(100)
        print('Overviews erfolgreich berechnet', flush=True)
        self.print_log.emit('Overviews erfolgreich berechnet')
        self.change_button_caption.emit('Start')
        # except Exception as err:
        #     print(err)

    def terminateThread(self):
        self.change_button_caption.emit('Start')
        self.print_log.emit('Vorgang abgebrochen')
        self.show_progress.emit(0)
        self.terminate()

and the functions for comunicating with the ui:

@Slot(str)
def printLog(self, msg):
    self.ui.list_status.addItem(msg)

@Slot(int)
def showProgress(self, value):
    self.ui.progressBar.setValue(value)

@Slot(str)
def changeCaption(self, txt):
    self.ui.btn_start_mbtiles.setText(txt)
Myrkjartan
  • 166
  • 3
  • 16
  • You'd better provide complete code that can reproduce the problem, or at lease a version with `sleep()`. Also it is generally a bad idea to terminate a thread from outside. More common apporoach that thead itself checks some variable and decides to or not to return from it's main function. – Rugnar Sep 09 '20 at 12:44

1 Answers1

0

Looks like gdal library is a binding - non-python code is called from python. So python's terminate() just can't stop it until execution returned to the python part. If you need to terminate your function immediatly, you may use processes instead of threads.

This may be helpful:

Is it possible to run function in a subprocess without threading or writing a separate file/script.

Rugnar
  • 2,894
  • 3
  • 25
  • 29
  • i took the code from the run() methode of the thread and made a function from it that i started within a new Process. I also tried subprocess.Popen. But it's always the same. The button i need to click to terminate the process is blocked. – Myrkjartan Sep 10 '20 at 08:15