九PyQt5多线程编程

Posted Lvcx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了九PyQt5多线程编程相关的知识,希望对你有一定的参考价值。

(三)多线程编程

      如果一次只完成一件事情,那是一个不错的想法,但事实上很多事情都是同时进行的,所以在Python中为了模拟这种状态,引入了线程机制,简单地说,当程序同时完成多件事情时,就是所谓的多线程程序。多线程应用广泛,开发人员可以使用多线程程序对要执行的操作分段执行,这样可以大大提高程序的运行速度和性能
      我们先对线程的分类及概述做简单介绍,然后详细讲解Python中进行线程编程的主要两个类——QTimer计时器类、QThread线程类,并对线程的具体实现进行详细讲解。之后,我们就可以熟悉使用Python进行线程编程的基础知识,并在实际开发中应用线程处理多任务问题。

1. 线程概述

      世间万物都会同时完成很多工作,例如,人体同时进行呼吸、血液循环、思考问题等活动,用户既可以使用计算机听歌,又可以使用它打印文件,而这些活动完全可以同时进行,这种思想放在Python中被称为并发,而将并发完成的每一件事情称为线程。

1. 线程的定义与分类

      先了解一个概念——进程。系统中资源分配和资源调度的基本单位,叫做进程。其实进程很常见,我们使用的QQ、Word、甚至是输入法等,每个独立执行的程序在系统中都是一个进程
      每个进程中都可以同时包含多个线程,例如,QQ是一个聊天软件,但它的功能有很多,如收发信息、播放音乐、查看网页和下载文件等,这些工作可以同时运行并且互不干扰,这就是使用了线程的并发机制,我们把QQ这个软件看作一个进程,而它的每一个功能都是一个可以独立运行的线程。

      上面介绍了一个进程可以包括多个线程,但计算机的CPU只有一个,那么这些线程是怎么做到并发运行的呢?Windows操作系统是多任务操作系统,它以进程为单位,每个独立执行的程序称为进程,在系统中可以分配给每个进程一段有限的使用CPU的时间(也可以称为CPU时间片),CPU在片段时间中执行某个进程,然后下一个时间片又跳至另一个进程中去执行。由于CPU转换较快,所以使得每个进程好像是同时执行一样。

      一个线程则是进程中的执行流程,一个进程中可以同时包括多个线程,每个线程也可以得到一小段程序的执行时间,这样一个进程就可以具有多个并发执行的线程。

2. 多线程的优缺点

      一般情况下,需要用户交互的软件都必须尽可能快地对用户的操作做出反应,以便提供良好的用户体验,但同时它又必须执行必要的计算以便尽可能快地将数据呈现给用户,这时可以使用多线程来实现。

1. 多线程的优点

      要提高对用户的相应速度,使用多线程是一种最有效的方式,在具有一个处理器的计算机上,多线程可以通过利用用户事件之间很小的时间段在后台处理数据来达到这种效果。多线程的优点如下:

  • 通过网络与Web服务器和数据库进行通信。
  • 执行占用大量时间的操作。
  • 区分具有不同优先级的任务。
  • 使用户界面可以在将时间分配给后台任务时仍能快速做出响应。

2. 多线程的缺点

多线程有好处,同时也有坏处,建议一般不要在程序中使用太多的线程,这样可以最大限度地减少操作系统资源的使用,并提高性能。使用多线程可能对程序造成的负面影响如下:

  • 系统将为进程和线程所需的上下文信息使用内存。因此,可以创建的进程和线程的数目会受到可用内存的限制。
  • 跟踪大量的线程将占用大量的处理器时间。如果线程过多,则其中大多数线程都不会产生明显的进度。如果大多数线程处于一个进程中,则其他进程中的线程的调度频率就会很低。
  • 使用多个线程控制代码执行非常复杂,并可能产生许多Bug。
  • 销毁线程需要了解可能发生的问题并进行处理。

在PyQt5中实现多线程主要有两种方法,一种是使用QTimer计时器模块;另一种是使用QThread线程模块

2. QTimer:计时器

      在PyQt5程序中,如果需要周期性地执行某项操作,就可以使用QTimer类实现,QTimer类表示计时器,它可以定期发射timeout信号,时间间隔的长度在start()方法中指定,以毫秒为单位,如果要停止计时器,则需要使用stop()方法。
在使用QTimer类时,首先需要进行导入:

from PyQt5.QtCore import QTimer

示例:双色球彩票选号器

      使用PyQt5实现模拟双色球选号的功能。
      (1)在PyQt5的Qt Designer设计器中创建一个窗口,设置背景,并添加7个Label标签和两个PushButton按钮。
      (2)将设计的窗口保存为.ui文件,并使用PyUIC工具将其转换为.py文件,同时使用qrcTOpy工具将用到的存储图片的资源文件转换为.py文件。这部分的代码如下:

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(435, 294)
        MainWindow.setWindowTitle("双色球彩票选号器")    # 设置窗口标题
        # 设置窗口背景图片
        MainWindow.setStyleSheet("border-image: url(./image/双色球彩票选号器.png)")
        self.centralwidget=QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        # 创建第一个红球数字的标签
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(97, 178,31, 31))
        # 设置标签的字体
        font = QtGui.QFont()    # 创建字体对象
        font.setPointSize(16)    # 设置字体大小
        font.setBold(True)      # 设置粗体
        font.setWeight(75)    # 设置字体
        self.label.setFont(font)    # 为标签设置字体
        # 设置标签的文字颜色
        self.label.setStyleSheet("color:rgb(255,255,255);")
        self.label.setObjectName("label")

        # 第2、3、4、5、6个红球和一个蓝球标签的代码的创建及设置代码与第一个红球标签的代码一样
        # 创建第2个红球
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(128, 178, 31, 31))
        self.label_2.setFont(font)  # 为标签设置字体
        self.label_2.setStyleSheet("color:rgb(255,255,255);")  # 设置标签的文字颜色
        self.label_2.setObjectName("label_2")
        # 创建第3个红球
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setGeometry(QtCore.QRect(159, 178, 31, 31))
        self.label_3.setFont(font)  # 为标签设置字体
        self.label_3.setStyleSheet("color:rgb(255,255,255);")  # 设置标签的文字颜色
        self.label_3.setObjectName("label_3")
        # 创建第4个红球
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        self.label_4.setGeometry(QtCore.QRect(190, 178, 31, 31))
        self.label_4.setFont(font)  # 为标签设置字体
        self.label_4.setStyleSheet("color:rgb(255,255,255);")  # 设置标签的文字颜色
        self.label_4.setObjectName("label_4")
        # 创建第个5红球
        self.label_5 = QtWidgets.QLabel(self.centralwidget)
        self.label_5.setGeometry(QtCore.QRect(221, 178, 31, 31))
        self.label_5.setFont(font)  # 为标签设置字体
        self.label_5.setStyleSheet("color:rgb(255,255,255);")  # 设置标签的文字颜色
        self.label_5.setObjectName("label_5")
        # 创建第6个红球
        self.label_6 = QtWidgets.QLabel(self.centralwidget)
        self.label_6.setGeometry(QtCore.QRect(252, 178, 31, 31))
        self.label_6.setFont(font)  # 为标签设置字体
        self.label_6.setStyleSheet("color:rgb(255,255,255);")  # 设置标签的文字颜色
        self.label_6.setObjectName("label_6")
        # 创建第7个红球
        self.label_7 = QtWidgets.QLabel(self.centralwidget)
        self.label_7.setGeometry(QtCore.QRect(283, 178, 31, 31))
        self.label_7.setFont(font)  # 为标签设置字体
        self.label_7.setStyleSheet("color:rgb(255,255,255);")  # 设置标签的文字颜色
        self.label_7.setObjectName("label_7")

        # 创建“开始”按钮
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(310, 235, 51, 51))
        # 设置按钮的背景图片
        self.pushButton.setStyleSheet("border-image: url(./image/开始.png);")
        self.pushButton.setText("")
        self.pushButton.setObjectName("pushButton")
        # 创建“停止”按钮
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(370, 235, 51, 51))
        # 设置按钮的背景图片
        self.pushButton_2.setStyleSheet("border-image: url(./image/停止.png);")
        self.pushButton_2.setText("")
        self.pushButton_2.setObjectName("pushButton_2")
        MainWindow.setCentralWidget(self.centralwidget)
        # 初始化双色球数字的Label标签的默认文本
        self.label.setText("00")
        self.label_2.setText("00")
        self.label_3.setText("00")
        self.label_4.setText("00")
        self.label_5.setText("00")
        self.label_6.setText("00")
        self.label_7.setText("00")
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

      (3)由于使用Qt Designer设计器设置窗口时,控件的背景默认会跟随窗口的背景,所以在.py文件的setupUi()方法中将7个Label标签的背景设置透明。

        # 设置显示双色球数字的Label标签背景透明
        self.label.setAtrribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_2.setAtrribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_3.setAtrribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_4.setAtrribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_5.setAtrribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_6.setAtrribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_7.setAtrribute(QtCore.Qt.WA_TranslucentBackground)

      (4)然后定义3个槽函数strat()、num()和stop(),分别用来开始计时器、随机生成双色球数字、停止计时器的功能。

# 自定义槽函数,用来开始计时器
    def start(self):
        self.timer = QTimer(MainWindow)    # 创建计时器对象
        self.timer.start()     # 开始计时器
        self.timer.timeout.connect(self.num)      # 设置计时器要执行的槽函数

    # 定义槽函数,用来设置7个Label标签中的数字
    def num(self):
        import random
        self.label.setText("0:02d".format(random.randint(1, 33)))     # 随机生成第一个红球数字
        self.label_2.setText("0:02d".format(random.randint(1, 33)))     # 随机生成第二个红球数字
        self.label_3.setText("0:02d".format(random.randint(1, 33)))     # 随机生成第三个红球数字
        self.label_4.setText("0:02d".format(random.randint(1, 33)))     # 随机生成第四个红球数字
        self.label_5.setText("0:02d".format(random.randint(1, 33)))     # 随机生成第五个红球数字
        self.label_6.setText("0:02d".format(random.randint(1, 33)))     # 随机生成第六个红球数字
        self.label_7.setText("0:02d".format(random.randint(1, 16)))     # 随机生成蓝球数字

    # 定义槽函数,用来停止计时器
    def stop(self):
        self.timer.stop()

      由于用到了random随机数类和QTimer类,所以需要导入相应的模块。

from PyQt5.QtCore import QTimer
import random

      (5)在.py文件的setupUi()方法中为“开始”和“停止”按钮的clicked信号绑定自定义的槽函数,以便在单击按钮时执行相应的操作。

		# 为“开始”按钮绑定单击信号
        self.pushButton.clicked.connect(self.start)
        # 为“停止”按钮绑定单击信号
        self.pushButton_2.clicked.connect(self.stop)

      (6)为.py文件添加__main__方法。

# 主函数
if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    global MainWindow
    MainWindow = QtWidgets.QMainWindow()     # 创建窗体对象
    ui = Ui_MainWindow()      # 创建PyQt5设计的窗体对象
    MainWindow.show()      # 调用PyQt5窗体的方法对窗体对象进行初始化设置
    ui.setupUi(MainWindow)     # 显示窗体
    sys.exit(app.exec_())     # 程序关闭时退出进程

完整的代码如下:

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QTimer


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(435, 294)
        MainWindow.setWindowTitle("双色球彩票选号器")    # 设置窗口标题
        # 设置窗口背景图片
        MainWindow.setStyleSheet("border-image: url(./image/双色球彩票选号器.png)")
        self.centralwidget=QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        # 创建第一个红球数字的标签
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(97, 178,31, 31))
        # 设置标签的字体
        font = QtGui.QFont()    # 创建字体对象
        font.setPointSize(16)    # 设置字体大小
        font.setBold(True)      # 设置粗体
        font.setWeight(75)    # 设置字体
        self.label.setFont(font)    # 为标签设置字体
        # 设置标签的文字颜色
        self.label.setStyleSheet("color:rgb(255,0,0);")
        self.label.setObjectName("label")

        # 第2、3、4、5、6个红球和一个蓝球标签的代码的创建及设置代码与第一个红球标签的代码一样
        # 创建第2个红球
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        # self.label_2.setGeometry(QtCore.QRect(128, 178, 31, 31))
        self.label_2.setGeometry(QtCore.QRect(134, 178, 31, 31))
        self.label_2.setFont(font)  # 为标签设置字体
        self.label_2.setStyleSheet("color:rgb(255,0,0);")  # 设置标签的文字颜色
        self.label_2.setObjectName("label_2")
        # 创建第3个红球
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        # self.label_3.setGeometry(QtCore.QRect(159, 178, 31, 31))
        self.label_3.setGeometry(QtCore.QRect(171, 178, 31, 31))
        self.label_3.setFont(font)  # 为标签设置字体
        self.label_3.setStyleSheet("color:rgb(255,0,0);")  # 设置标签的文字颜色
        self.label_3.setObjectName("label_3")
        # 创建第4个红球
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        # self.label_4.setGeometry(QtCore.QRect(190, 178, 31, 31))
        self.label_4.setGeometry(QtCore.QRect(205, 178, 31, 31))
        self.label_4.setFont(font)  # 为标签设置字体
        self.label_4.setStyleSheet("color:rgb(255,0,0);")  # 设置标签的文字颜色
        self.label_4.setObjectName("label_4")
        # 创建第个5红球
        self.label_5 = QtWidgets.QLabel(self.centralwidget)
        # self.label_5.setGeometry(QtCore.QRect(221, 178, 31, 31))
        self.label_5.setGeometry(QtCore.QRect(239, 178, 31, 31))
        self.label_5.setFont(font)  # 为标签设置字体
        self.label_5.setStyleSheet("color:rgb(255,0,0);")  # 设置标签的文字颜色
        self.label_5.setObjectName("label_5")
        # 创建第6个红球
        self.label_6 = QtWidgets.QLabel(self.centralwidget)
        # self.label_6.setGeometry(QtCore.QRect(252, 178, 31, 31))
        self.label_6.setGeometry(QtCore.QRect(273, 178, 31, 31))
        self.label_6.setFont(font)  # 为标签设置字体
        self.label_6.setStyleSheet("color:rgb(255,0,0);")  # 设置标签的文字颜色
        self.label_6.setObjectName("label_6")
        # 创建第7个红球
        self.label_7 = QtWidgets.QLabel(self.centralwidget)
        self.label_7.setGeometry(QtCore.QRect(283, 178, 31, 31))
        self.label_7.setGeometry(QtCore.QRect(307, 178, 31, 31))
        self.label_7.setFont(font)  # 为标签设置字体
        self.label_7.setStyleSheet("color:rgb(0,0,255);")  # 设置标签的文字颜色
        self.label_7.setObjectName("label_7")

        # 创建“开始”按钮
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(310, 235, 51, 51))
        # 设置按钮的背景图片
        self.pushButton.setStyleSheet("border-image: url(./image/开始.png);")
        self.pushButton.setText("")
        self.pushButton.setObjectName("pushButton")
        # 创建“停止”按钮
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(370, 235, 51, 51))
        # 设置按钮的背景图片
        self.pushButton_2.setStyleSheet("border-image: url(./image/停止.png);")
        self.pushButton_2.setText("")
        self.pushButton_2.setObjectName("pushButton_2")
        MainWindow.setCentralWidget(self.centralwidget)
        # 初始化双色球数字的Label标签的默认文本
        self.label.setText("00")
        self.label_2.setText("00")
        self.label_3.setText("00")
        self.label_4.setText("00")
        self.label_5.setText("00")
        self.label_6.setText("00")
        self.label_7.setText("00")
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        # 设置显示双色球数字的Label标签背景透明
        self.label.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_2.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_3.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_4.setAttribut

多线程编程学习笔记-基础

接上文 多线程编程学习笔记-基础(一)

接上文 多线程编程学习笔记-基础(二)

九、向线程传递参数

 1.代码如下。

 

using System;

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; //引入线程
using System.Diagnostics;
 

namespace ThreadConsoleApp
{

    class Program
    {
        static void Main(string[] args)
        {

            Console.WriteLine("开始,给线程传参数");          

            var fore = new ThreadBackground(10);   

            Thread t = new Thread(fore.CountNumber);
            t.Name = "线程1";         

            //启动线程

            t.Start();
            t.Join();
            Console.WriteLine("----------------------------"); 

            var t2 = new Thread(Count);
            t2.Name = "线程2";
            t2.Start(8);
            t2.Join();
            Console.WriteLine("----------------------------"); 

            var t3 = new Thread(()=>CountNumber(12));
            t3.Name = "线程3";
            t3.Start();
            t3.Join();
            Console.WriteLine("----------------------------");

 

            int i = 10;
            var t4 = new Thread(() => PrintNumber(i));
            t4.Name = "线程4";
            i = 20;
            var t5 = new Thread(() => PrintNumber(i));
            t5.Name = "线程5";
            t4.Start();
            t5.Start();
            Console.Read();
        }

        static void CountNumber(int cnt)
        {
            for (int i = 0; i < cnt; i++)
            {

                Thread.Sleep(500);
                Console.WriteLine(string.Format(" {0}    打印 {1,11} 数字", Thread.CurrentThread.Name, i.ToString("N0")));

            }

        }

        static void Count(object cnt)
        {
            CountNumber((int)cnt);
        }
        static void PrintNumber(int num)
        {        

            Console.WriteLine(string.Format(" {0} 打印 {1,11} 数字", Thread.CurrentThread.Name, num.ToString("N0")));         

        } 
    }
}

 

 

 2.结果如下图。

 

线程1,我们通过实例化对象来进行参数传递。

线程2,我们使用Thread.Start()来传递参数,不过此方法只接收单个参数,而且是对象类型。

线程3,我们使用lambda表达式进行参数传递,lambda表达式定义了一个不属于任何类的方法,同时该方法调用了我们实际要执行的方法,同时传递参数给线程。

线程4与线程5,则是显示了使用lambda表达式进行参数传递的一个问题,即当多个lambda表达式共用一个变量时,它们会共享这个变量的值。如图中线程4与线程5所显示,没有打印10,只打印了20。

 

十、使用lock锁定操作

 1.代码如下

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; //引入线程
using System.Diagnostics;
 

namespace ThreadConsoleApp
{
    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine("开始,给线程加锁");           

            var c = new Counter();           

            Thread t = new Thread(()=>Count(c));
            var t3 = new Thread(() => Count(c));

             var t2 = new Thread(() => Count(c));
            t.Name = "线程1";         

            //启动线程
            t.Start();
         

            t2.Name = "线程2";
            t2.Start();     
 
            t3.Name = "线程3";
            t3.Start();
            t.Join();
            t2.Join();     
            t3.Join();
            Console.WriteLine(string.Format("没有加锁的多线程总计:{0}",c.Count));
            Console.WriteLine("----------------------------");


            var c1 = new CounterLock();
            var t4 = new Thread(() => Count(c1));
            t4.Name = "线程4";
           

            var t5 = new Thread(() => Count(c1));
            t5.Name = "线程5";
            var t6 = new Thread(() => Count(c1));
            t6.Name = "线程6";

            t4.Start();
            t5.Start();
            t6.Start();
            t4.Join();
            t5.Join();
            t6.Join();
            Console.WriteLine(string.Format("加锁的多线程总计:{0}", c1.Count));
            Console.Read();
        }      

        static void Count(CountBase cnt)
        {
            for (int i = 0; i < 100000; i++)
            {
                cnt.Incerement();
                cnt.Dncerement();

            }
        }
     }

    abstract class CountBase
    {
         public abstract void  Incerement();
        public abstract void Dncerement();
    }

    class Counter : CountBase
    {
        public int Count { get; private set; }
        public override void Dncerement()
        {
            Count--;
        }

        public override void Incerement()
        {

            Count++;
        }
    }

    class CounterLock : CountBase
    {
        private readonly object objSync = new object();
        public int Count { get; private set; }
        public override void Dncerement()
        {
            lock (objSync)
            {
                Count--;
            }       
        }

        public override void Incerement()
        {
            lock (objSync)
            {
                Count++;
            }
        }
    }

}

 

2. 结果如下图

 

      主线程首先创建了一个 Counter的实例对象,这个类定义了一个可以增,可以 减的简单计数器。然后我们创建了三个线程,这三个线程共享一个Counter对象。由于没有对共享变量的锁定,所以在一个周期内,对共享变量的改变,在上个线程没结束之前,当前线程又对共享变量进行了操作,我们会得到不同的计数值,如上图所示。为了防止这种情况的发生,所以我们要对共享变量进行加锁。使用lock关键字锁定对象,这样在一个线程操作完成之前,其他线程都不能对共享变量进行操作。

 

十一、Moniter对资源的锁定

 1.代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; //引入线程
using System.Diagnostics; 

namespace ThreadConsoleApp
{   
 class Program
    {
        static void Main(string[] args)
        {

            Console.WriteLine("开始,线程死锁");          

            var lock1 = new object();
            var lock2 = new object();
           

            Thread t = new Thread(()=> DeadLock(lock1,lock2));
            t.Name = "线程1";       

            //启动线程

            t.Start();
            lock (lock2)
            {
                Thread.Sleep(2000); 

                if (Monitor.TryEnter(lock1,TimeSpan.FromSeconds(5)))

                {
                    Console.WriteLine("在规定时间内,请求资源");

                }
                else

                {
                    Console.WriteLine("超时,无法获取资源");

                }
            }

            new Thread(() => DeadLock(lock1, lock2)).Start();
             Console.WriteLine("-----------------------------");

            lock (lock2)
            {

                Thread.Sleep(1000);
                Console.WriteLine(string.Format("死锁线程"));

               lock(lock1)
                {
                    Console.WriteLine("请求资源成功");

                }          
           }

            Console.Read();
        }
      

        /// <summary>
        /// 死锁方法
        /// </summary>
        /// <param name="objLock1"></param>
        /// <param name="objLock2"></param>
        static void DeadLock(object objLock1,object objLock2)
        {
            lock (objLock1)
            {
                Thread.Sleep(2000);
                lock (objLock2)
                {
                    Console.WriteLine("死锁");
                }
            }
        }
    }
}

2.结果如下图

 

 先看deadlock方法,这个方法先锁定lock1对象,然后等待2秒之后,锁定了lock2对象。然后在子线程中启动了这个方法。

主线程中先锁定了lock2对象,然后等待获取lock1对象。由于子线程锁定了lock1对象,等待lock2对象。所以造成了死锁。

 

十二、多线程的异常处理

 1.代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; //引入线程
using System.Diagnostics;
 
namespace ThreadConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {

            Console.WriteLine("开始,异常处理");          
            Thread t = new Thread(FaultyThread);
            t.Name = "线程1";        

            //启动线程
            t.Start();
            t.Join();
            try
            {
                t = new Thread(ExpectThread);
                t.Start();
            }

            catch (Exception ex)
            {
                Console.WriteLine("异常信息:" + ex.Message);
            }
            Console.Read();
        }    

        static void ExpectThread()
        {
            Console.WriteLine(string.Format("异常处理"));
            Thread.Sleep(2000);
            throw new Exception("抛出异常");
        }
        static void FaultyThread()
        {
            try
            {
                Console.WriteLine(string.Format("异常处理2"));
                Thread.Sleep(1000);
                throw new Exception("抛出异常2");
            }

            catch (Exception ex)
            {
                Console.WriteLine(string.Format("异常处理2:{0}",ex.Message));
            }        

        }
    }
}

 

 2.结果如下图。

 

 在程序中定义了两个处理异常的方法,一个对异常进行了处理,另一个没有对异常进行处理。最后如图。程序崩溃了。

以上是关于九PyQt5多线程编程的主要内容,如果未能解决你的问题,请参考以下文章

PyQt5中多线程模块QThread解决界面卡顿无响应问题,线程池ThreadPoolExecutor解决多任务耗时操作问题

PyQt5中多线程模块QThread解决界面卡顿无响应问题,线程池ThreadPoolExecutor解决多任务耗时操作问题

PyQt5中多线程模块QThread解决界面卡顿无响应问题,线程池ThreadPoolExecutor解决多任务耗时操作问题

python并发编程之多线程

python并发编程之多线程

python并发编程之多线程