线程

线程篇(主线程(UI线程),后台线程,线程池线程) 后续不间断增加、提示:以下是本篇文章正文内容,下面案例可供参考总之,不同的线程类型适用于不同的场景,我们需要根据具体的需求来选择合适的线程类型。在使用线程时,我们需要注意线程的生命周期、同步机制、异常处理、性能优化等方面的问题,以保证线程的稳定性和可靠性。 阅读详情

 线程Thread

什么是线程

image-20211204102521781

线程(Thread)特点:

  1. 线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位
  2. 线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;
  3. 一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;
  4. 拥有自己独立的栈和共享的堆,共享堆,不共享栈,标准线程由操作系统调度;
  5. 调度和切换:线程上下文切换比进程上下文切换要快得多。

线程的创建方式

Python的标准库提供了两个模块:_thread和threading,

_thread是低级模块,threading是高级模块,

对_thread进行了封装。

绝大多数情况下,我们只需要使用threading这个高级模块。

线程的创建可以通过分为两种方式:

1. 方法包装

2. 类包装

线程的执行统一通过start()方法

线程的创建方式(方法包装)

#encoding = utf-8
from threading import Thread
from time import sleep

#创建方法a1
def a1(name):
    print(f'线程{name},start')
    for i in range(3):
        print(f'线程{name},{i}')
        sleep(1)            # 睡一秒
    print(f'线程{name},end')

if __name__ == '__main__':
    #主线程启动
    print('主线程,start')
    #方法创建线程t1,t2
    t1 = Thread(target=a1,args=('t1',)) #target代表此线程启动执行的方法
    t2 = Thread(target=a1,args=('t2',)) #args  代表此线程启动传入的参数,参数为元组

    #启动创建的线程
    t1.start()
    t2.start()
    print('主线程,end')

运行结果可能会出现换行问题,是因为多个线程抢夺控制台输出的IO流,是正常情况。

线程的创建方式(类包装)

#encoding = utf-8
from threading import Thread
from time import sleep

#定义类,继承Thread
class MyThread(Thread):
    #初始化
    def __init__(self,name):
        Thread.__init__(self)
        self.name = name
    #重写run方法
    def run(self):
        print(f'线程{self.name},start')
        for i in range(3):
            print(f'线程{self.name},{i}')
            sleep(1)  # 睡一秒
        print(f'线程{self.name},end')

if __name__ == '__main__':
    print('主线程,start')
    #类方法创建线程t1,t2
    t1 = MyThread('t1')
    t2 = MyThread('t2')

    #启动创建的线程
    t1.start()  #执行run方法
    t2.start()
    print('主线程,end')

join()

之前的代码,主线程不会等待子线程结束。

如果需要等待子线程结束后,再结束主线程,可使用join()方法。

#encoding = utf-8
from threading import Thread
from time import sleep


#创建方法a1
def a1(name):
    print(f'线程{name},start')
    for i in range(3):
        print(f'线程{name},{i}')
        sleep(1)            # 睡一秒
    print(f'线程{name},end')

if __name__ == '__main__':
    #主线程启动
    print('主线程,start')
    #创建线程t1
    t1 = Thread(target=a1,args=('t1',)) #target代表此线程启动执行的方法
    t2 = Thread(target=a1,args=('t2',)) #args  代表此线程启动传入的参数,参数为元组

    #启动创建的线程
    t1.start()
    t2.start()

    #join()使线程t1,t2结束后,主线程才能结束
    t1.join()
    t2.join()
    print('主线程,end')

守护线程

在行为上还有一种叫守护线程,主要的特征是它的生命周期。

主线程死亡,它也就随之死亡。在python中,线程通过setDaemon(True|False)来设置是否为守护线程。

守护线程的作用:

  • 守护线程作用是为其他线程提供便利服务,守护线程最典型的应用就是 GC (垃圾收集器)。
#encoding = utf-8
from threading import Thread
from time import sleep

#创建方法a1
def a1(name):
    print(f'线程{name},start')
    for i in range(3):
        print(f'线程{name},{i}')
        sleep(1)            # 睡一秒
    print(f'线程{name},end')

if __name__ == '__main__':
    #主线程启动
    print('主线程,start')
    #创建线程t1
    t1 = Thread(target=a1,args=('t1',))
    
    #守护线程,主线程结束后,线程t1也随之消亡
    t1.daemon = True
    #启动创建的线程
    t1.start()

全局锁GIL问题

image-20211205160649667

在python中,无论你有多少核,在Cpython解释器中永远都是假象。无论你是4核,8核,还是16核.......不好意思,同一时间执行的线程只有一个线程,它就是这个样子的。这个是python的一个开发时候,设计的一个缺陷,所以说python中的线程是“含有水分的线程”。

Python GIL(Global Interpreter Lock)

Python代码的执行由Python 虚拟机(也叫解释器主循环,CPython版本)来控制,Python 在设计之初就考虑到要在解释器的主循环中,同时只有一个线程在执行,即在任意时刻,只有一个线程在解释器中运行。对Python 虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。

image-20211204114226986

⚠️GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行,就没有GIL的问题。然而因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python,也就想当然的把GIL归结为Python语言的缺陷

线程同步和互斥锁

现实生活中,我们会遇到“同一个资源,多个人都想使用”的问题。

比如:教室里,只有一台电脑,多个人都想使用。天然的解决办法就是,在电脑旁边,大家排队。前一人使用完后,后一人再使用。再比如,上厕所排队。

image-20211204114847733

线程同步

处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象。 这时候,我们就需要用到“线程同步”。 线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面的线程使用完毕后,下一个线程再使用。

image-20211204115631990

【示例】多线程操作同一个对象(未使用线程同步)

#encoding = utf-8
from threading import Thread
from time import sleep

#账户(包含名称与余额)
class Account:
    def __init__(self,name,money):
        self.name = name
        self.money = money

class Drawing(Thread):
    def __init__(self,drawingNum,account): #drawingNum表示取钱的金额
        Thread.__init__(self)
        self.drawingNum = drawingNum
        self.account = account
        self.expenseTotal = 0            #表示取钱的总金额累计多少

    def run(self):
        if self.account.money<self.drawingNum:
            return

        #模拟线程不同步会出现的问题
        sleep(1)            #线程1睡眠时,还没有取钱,余额不变,导致线程2判断余额足够

        self.account.money-=self.drawingNum
        self.expenseTotal+=self.drawingNum
        print(f"账户:{self.account.name},总共取了:{self.expenseTotal}")
        print(f"账户:{self.account.name},余额是:{self.account.money}")


if __name__ == '__main__':
    a1 = Account('张三',100)
    draw1 = Drawing(80,a1) # 定义取钱线程对象1;
    draw2 = Drawing(80,a1) # 定义取钱线程对象2;
    
    draw1.start()          # 第一次取钱
    draw2.start()          # 第二次取钱

两个线程同时操作同一个账户对象,竟然从只有100元的账户,轻松取出80*2=160元,账户余额竟然成为了-60。这是由于没有线程同步机制,导致的问题。

我们可以通过“锁机制”来实现线程同步问题,锁机制有如下几个要点:

  1. 必须使用同一个锁对象
  2. 互斥锁的作用就是保证同一时刻只能有一个线程去操作共享数据,保证共享数据不会出现错误问题
  3. 使用互斥锁的好处确保某段关键代码只能由一个线程从头到尾完整地去执行
  4. 使用互斥锁会影响代码的执行效率
  5. 同时持有多把锁,容易出现死锁的情况
互斥锁

互斥锁: 对共享数据进行锁定,保证同一时刻只能有一个线程去操作。

注意: 互斥锁是多个线程一起去抢,抢到锁的线程先执行,没有抢到锁的线程需要等待,等互斥锁使用完释放后,其它等待的线程再去抢这个锁。

threading模块中定义了Lock变量,这个变量本质上是一个函数,通过调用这个函数可以获取一把互斥锁。

【示例】多线程操作同一个对象(增加互斥锁,使用线程同步)

#encoding = utf-8
from threading import Thread,Lock
from time import sleep

#账户(包含名称与余额)
class Account:
    def __init__(self,name,money):
        self.name = name
        self.money = money

class Drawing(Thread):
    def __init__(self,drawingNum,account): #drawingNum表示取钱的金额
        Thread.__init__(self)
        self.drawingNum = drawingNum
        self.account = account
        self.expenseTotal = 0            #表示取钱的总金额累计多少

    def run(self):
        #acquire和release方法之间的代码同一时刻只能有一个线程去操作
        lock.acquire()
        if self.account.money<self.drawingNum:
            return

        #模拟线程不同步会出现的问题
        sleep(1)             #线程1睡眠时,还没有取钱,余额不变,导致线程2判断余额足够

        self.account.money-=self.drawingNum
        self.expenseTotal+=self.drawingNum
        lock.release()

        print(f"账户:{self.account.name},总共取了:{self.expenseTotal}")
        print(f"账户:{self.account.name},余额是:{self.account.money}")


if __name__ == '__main__':
    a1 = Account('张三',100)
    #使用互斥锁
    lock = Lock()
    draw1 = Drawing(80,a1) # 定义取钱线程对象1;
    draw2 = Drawing(80,a1) # 定义取钱线程对象2;

    draw1.start()          # 第一次取钱
    draw2.start()          # 第二次取钱
  • acquire和release方法之间的代码同一时刻只能有一个线程去操作
  • 如果在调用acquire方法的时候 其他线程已经使用了这个互斥锁,那么此时acquire方法会堵塞,直到这个互斥锁释放后才能再次上锁。

死锁问题和解决方案

死锁

在多线程程序中,死锁问题很大一部分是由于一个线程同时获取多个锁造成的。

举例:有两个人都要做饭,都需要“锅”和“菜刀”才能炒菜。

image-20211204120613276

from threading import Thread, Lock
from time import sleep

def fun1():
  lock1.acquire()
  print('fun1拿到锁1')
  sleep(2)
  lock2.acquire()
  print('fun1去拿锁2')

  lock2.release()
  print('fun1释放锅')
  lock1.release()
  print('fun1释放锁1')


def fun2():
  lock2.acquire()
  print('fun2拿到锁2')
  lock1.acquire()
  print('fun2去拿锁1')
  lock1.release()
  print('fun2释放锁1')
  lock2.release()
  print('fun2释放锁2')


if __name__ == '__main__':
  lock1 = Lock()
  lock2 = Lock()

  t1 = Thread(target=fun1)
  t2 = Thread(target=fun2)
  t1.start()
  t2.start()

由于方法1拿了锁1,想要拿到锁2再释放锁1,

可是方法2拿了锁2没有释放,导致方法1不能去拿到锁2了 

死锁的解决方法

死锁是由于“同步块需要同时持有多个锁造成”的,要解决这个问题,思路很简单,就是:

同一个代码块,不要同时持有两个对象锁。

信号量(Semaphore)

image-20211205103148977

互斥锁使用后,一个资源同时只有一个线程访问。如果某个资源,我们同时想让N个(指定数值)线程访问?这时候,可以使用信号量。

信号量控制同时访问资源的数量。信号量和锁相似,锁同一时间只允许一个对象(进程)通过,信号量同一时间允许多个对象(进程)通过。

应用场景

  1. 在读写文件的时候,一般只能只有一个线程在写,而读可以有多个线程同时进行,如果需要限制同时读文件的线程个数,这时候就可以用到信号量了(如果用互斥锁,就是限制同一时刻只能有一个线程读取文件)。
  2. 在做爬虫抓取数据时。

底层原理

信号量底层就是一个内置的计数器。每当资源获取时(调用acquire)计数器-1,资源释放时(调用release)计数器+1。

from threading import Thread, Lock, Semaphore
from time import sleep

def home(name,se):
  #拿到锁
  se.acquire()
  print(f'{name}进入房间')
  sleep(2)
  print(f'{name}离开房间')
  #释放锁
  se.release()



if __name__ == '__main__':
  #创建信号量为2
  se = Semaphore(2)
  #创建7个线程
  for i in range(7):
    t = Thread(target=home,args=(f'tom{i}',se))
    t.start()

事件(Event)

事件Event主要用于唤醒正在阻塞等待状态的线程;

image-20211205104512869

原理

Event 对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。在初始情况下,event 对象中的信号标志被设置假。如果有线程等待一个 event 对象,而这个 event 对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。一个线程如果将一个 event 对象的信号标志设置为真,它将唤醒所有等待个 event 对象的线程。如果一个线程等待一个已经被设置为真的 event 对象,那么它将忽略这个事件,继续执行

Event()可以创建一个事件管理标志,该标志(event)默认为False,event对象主要有四种方法可以调用:

方法名说明
event.wait(timeout=None)调用该方法的线程会被阻塞,如果设置了timeout参数,超时后,线程会停止阻塞继续执行;
event.set()将event的标志设置为True,调用wait方法的所有线程将被唤醒
event.clear()将event的标志设置为False,调用wait方法的所有线程将被阻塞
event.is_set()判断event的标志是否为True

【示例】Event事件对象经典用法

#coding:utf-8
import threading
import time

def chihuoguo(name):
  #等待事件,进入等待阻塞状态
  print(f'{name}已经启动')
  print(f'小伙伴{name}已经进入就餐状态!')
  time.sleep(1)
  event.wait()
  # 收到事件后进入运行状态
  print(f'{name}收到通知了.' )
  print(f'小伙伴{name}开始吃咯!')

if __name__ == '__main__':
  
  #创建阻塞线程的event对象
  event = threading.Event()
  # 创建新线程
  thread1 = threading.Thread(target=chihuoguo, args=("tom", ))
  thread2 = threading.Thread(target=chihuoguo, args=("cherry", ))
  # 开启线程
  thread1.start()
  thread2.start()

  time.sleep(5)
  # 发送事件通知
  print('---->>>主线程通知小伙伴开吃咯!')
  event.set()

生产者和消费者模式

image-20211205110140846

多线程环境下,我们经常需要多个线程的并发和协作。这个时候,就需要了解一个重要的多线程并发协作模型“生产者/消费者模式”。

image-20211205104655764

什么是生产者?

生产者指的是负责生产数据的模块(这里模块可能是:方法、对象、线程、进程)。

什么是消费者?

消费者指的是负责处理数据的模块(这里模块可能是:方法、对象、线程、进程)

什么是缓冲区?

消费者不能直接使用生产者的数据,它们之间有个“缓冲区”。

生产者将生产好的数据放入“缓冲区”,消费者从“缓冲区”拿要处理的数据。

缓冲区是实现并发的核心,缓冲区的设置有3个好处:

  1. 实现线程的并发协作

有了缓冲区以后,生产者线程只需要往缓冲区里面放置数据,而不需要管消费者消费的情况;同样,消费者只需要从缓冲区拿数据处理即可,也不需要管生产者生产的情况。 这样,就从逻辑上实现了“生产者线程”和“消费者线程”的分离。

  1. 解耦了生产者和消费者

生产者不需要和消费者直接打交道

  1. 解决忙闲不均,提高效率

生产者生产数据慢时,缓冲区仍有数据,不影响消费者消费;消费者处理数据慢时,生产者仍然可以继续往缓冲区里面放置数据

缓冲区和queue对象

从一个线程向另一个线程发送数据最安全的方式可能就是使用 queue 库中的队列了。创建一个被多个线程共享的 Queue 对象,这些线程通过使用 put() 和 get()操作来向队列中添加或者删除元素。Queue 对象已经包含了必要的锁,所以你可以通过它在多个线程间多安全地共享数据。

#coding=utf-8
from queue import Queue
from threading import Thread
from time import sleep

def producer():   #生产者
  num = 1
  while True:
    if queue.qsize()<5:               #最多只能存放5个馒头
      print(f'生产:{num}号馒头')
      queue.put(f'{num}号馒头')       #将馒头放入框,使用了一次put,queue.qsize()数量+1
      num+=1
    else:
      print('馒头框满了')
    sleep(1)

def consumer():   #消费者
  while True:
    print(f'获取馒头:{queue.get()}')  #将馒头取出,使用了一次get,queue.qsize()数量-1
    #queue.get()可以被打印,打印的是queue.put括号里面的东西
    sleep(1)

if __name__ == '__main__':
    #创建queue对象,用来存放馒头
    queue = Queue()
    t1 = Thread(target=producer)  #生产馒头的线程
    t1.start()

    t2 = Thread(target=consumer)  #消费馒头的线程
    t2.start()

Linux 线程:使用&管理线程、多线程、分离线程 阅读详情

相关推荐

线程池的线程是如何复用的

进程和线程的关系相信大家都知道,这里我就不做过多的解释了,既然一个进程是由多个线程组成的,那么线程池又是由若干个线程队列组成的,在并发量比较高的情景下,我们通常会去创建线程池就执行任务,而不单一的创建多个线程去执行任务,因为线程的创建的一系列动作,是需要资源开销的,如果频繁的对线程创建销毁,其实本身是一种很浪费资源的,就更谈不上提高效率了。

m0_71777195的博客 2537

线程及线程池

本文章主要讲解线程及线程池部分的相关知识

2301_80365603的博客 1961

前台线程和后台线程、用户线程和守护线程

一、Java 分为两种线程:用户线程和守护线程 所谓守护线程是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称职的守护者,并且这种线程并不属于程序中不可或缺的部分。因 此,当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。 守护线程和用户线程的没啥本质的区别:唯一的不同之处就在于虚拟机的离开:...

程序员世杰 2745

一键了解线程、线程安全、线程池

一键了解线程、线程安全、线程池

HKTTT_的博客 2038

告别SendKeys!用DD驱动级模拟在Windows 10/11上实现真·后台键鼠操作(Python实战)

本文详细介绍了如何使用DD驱动级模拟技术在Windows 10/11上实现真后台键鼠操作,解决传统方法如pyautogui和SendKeys的局限性。通过Python实战案例,展示了驱动级模拟在游戏自动化、RPA等场景中的高效应用,包括环境配置、核心API解析及高级优化技巧。

weixin_42519985的博客 802

软件缺陷(定义+表现形式+优先级+信息+产生原因),看完这篇文章就懂了

软件缺陷软件缺陷的定义软件缺陷的表现形式软件缺陷产生的原因软件缺陷的根源软件缺陷的费用软件缺陷的信息 软件缺陷的定义 IEEE 1983 of IEEE Stardard 729中软件缺陷做了一个标准的定义: 从产品内部看,软件缺陷是软件产品开发或维护过程中所存在的错误、毛病等各种问题;从外部看,软件缺陷是系统所需要实现的某种功能的失效或违背。 因此软件缺陷就是软件产品中所存在的问题,最终表现为用户所需要的功能没有完全实现,没有满足用户的需求。 缺陷不是bug,缺陷包含bug,缺陷的范围更大。 软件缺陷

qq_40676418的博客 1万+

linux线程详解:线程概念、线程调度、线程安全、线程模型

(1)线程的组成:线程ID、当前指令指针(PC)、寄存器集合、堆栈;(2)一个进程包含一个或者多个线程,其中进程的大部分资源(代码段、数据段、堆段、打开文件/信号等)都是线程间共享的,线程会保留一部分私有数据(寄存器、栈);

weixin_42031299的博客 3583

树莓派4B+红外传感器:手把手教你DIY一个能走黑线的智能小车(Python代码全解析)

本文详细介绍了如何使用树莓派4B和红外传感器DIY一个智能循迹小车,包括硬件配置、GPIO连接、Python代码实现及优化算法。通过动态PWM调速、状态机设计和赛道记忆算法,提升小车的循迹性能和稳定性。适合初学者和电子爱好者动手实践。

weixin_29188043的博客 269

多线程,线程池,线程的创建,线程池的参数

​ 进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位。线程也被称为轻量级进程,线程是进程的组成部分,一个进程可以拥有多个线程,一个线程必须有一个父进程。线程可以拥有自己的堆栈、自己的程序计数器和自己的局部变量,但不拥有系统资源,它与父进程的其它线程共享该进程所拥有的全部资源。一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。

weixin_44797327的博客 1302

Windows下Python多版本共存与切换的终极指南(含环境变量详解)

本文详细解析了在Windows系统下实现Python多版本共存与切换的完整方案。通过深入讲解环境变量Path的底层机制,提供了从安装策略、精细化Path管理到创建快速切换脚本的实战指南,并介绍了py启动器和虚拟环境等高级技巧,帮助开发者彻底解决版本冲突问题,提升开发效率。

v6b7n8m9q0的博客 538

【多模态大模型】GLIP:零样本目标检测新范式与视觉语言理解

本文深入解析了多模态大模型GLIP在零样本目标检测和视觉语言理解领域的创新应用。GLIP通过统一目标检测与自然语言理解任务,实现了零样本学习能力,能够精准定位复杂文本描述对应的图像区域。文章详细介绍了GLIP的核心技术、数据策略及实战表现,并对比了与其他多模态模型的差异,为AI视觉理解提供了新范式。

weixin_29186249的博客 263

多线程——线程实现、线程状态、线程同步、线程通信、线程池

多线程一、线程1.普通方法调用和多线程2.程序、进行、线程二、线程创建1.继承Thread类2.实现Runable接口3.实现Callable接口4.静态代理模式5、Lamda表达式三、线程状态1.线程状态2.线程方法3.线程停止4.线程休眠sleep5.线程礼让5.join6.线程状态观测7.线程优先级8.守护(daemon)线程四、线程同步1.并发与并行2.线程同步——等待机制2.1 队列 和 锁2.2 线程同步2.3 同步方法2.4 同步块3.死锁4. Lock锁 一、线程 1.普通方法调用和多线程

weixin_44090845的博客 3771

Ubuntu零基础入门到精通【3.10讲】:旧版本 Ubuntu 升级与迁移路线:从 20.04 到 24.04 的完整实战指南

🏆 本文收录于 《滚雪球学 Ubuntu》 专栏。 本专栏面向有一定计算机基础,但尚未系统学习 Linux / Ubuntu 的读者,采用“滚雪球式学习法”:先装好、再会用、再理解、再优化、再实战,带你从第一次进入 Ubuntu 桌面 / 终端开始,逐步掌握 Ubuntu 的日常使用、命令操作、软件安装、系统配置、开发环境搭建与服务器部署能力。

**My Coding Family** 1248

JAVA线程、线程池解析

是操作系统能够进行的最小单位,它被包含在进程之中,是进程中的实际运作单位。进程是资源分配的基本单位,它拥有自己独立的地址空间和各种资源;而线程是处理机调度的基本单位,它只能和其他线程共享进程的资源,而。线程的上下文切换速度比进程快。

柔丽君的博客 1413

【VTKExamples::Meshes】第十二期 QuadricDecimation

本文分享VTK样例QuadricDecimation,并解析接口vtkQuadricDecimation,希望对各位小伙伴有所帮助!

qq_40041064的博客 343

YOLOv8集成CPCA(Combined Parallel Convolutional Attention)注意力机制模块YOLOv8深度教程

YOLOv8集成CPCA注意力模块教程摘要 本教程详细介绍了如何将YOLOv8 CPCA(Combined Parallel Convolutional Attention)注意力模块集成到YOLOv8目标检测框架中。CPCA模块结合了通道注意力和多尺度空间注意力机制,通过全局池化和双路径融合增强通道特征,并利用多尺度深度可分离卷积捕获空间上下文信息。YOLOv8 教程包含完整的实现步骤:创建CPCA模块代码、修改YOLOv8模型解析逻辑、编写自定义配置文件,YOLOv8YOLOv8YOLOv8YOLOv8

FJN110的博客 1620

易语言创建线程挂起线程恢复线程销毁线程

线程创建CreateThread,线程挂起SuspendThread,线程恢复ResumeThread,线程销毁TerminateThread,都是kernel32的命令,我们自己封装这些线程的命令,就是便于我们理解他们的工作机制。 API源码: .版本 2 .DLL命令 恢复线程, 整数型, "kernel32", "ResumeThread", , 恢复线程 .参数 hThread, 整数型, , 线程的句柄 .DLL命令 销毁线程, 整数型, "kernel32", "Termi

511遇见 1万+

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

线程 - 线程优缺点、线程自有和共享的数据、多线程使用公共空间、线程分离、线程库对线程的管理

在上面的【四、2. 线程自有的数据】部分,我们提及了线程有独立栈结构,现在我们看到它了, 线程的栈结构是在库中维护的,每个线程都有自己的独立栈结构,主线程使用的是地址空间中的栈空间,叫主线程栈。多线程切换有成本,像上面的计算密集型应用,线程过多可能会有较大的性能损失(增加了额外的同步和调度开销,而可用资源不变)。而进程创建的时空成本是较高的,有各种数据结构的创建,数据的加载。让两个线程进同一个线程函数,打印同一个临时变量的地址,是不一样的,说明使用的是不同的栈结构。而线程占用的都是一份的。

addicted_to的博客 1384

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Linux-多线程2 ——线程等待、线程异常、线程退出、线程取消和线程分离

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档。

fengjunziya的博客 1430

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

在子线程中创建子线程及线程查看方法

小结:我们看到,son线程的退出,并没有影响到孙线程的运行,因为进程并未退出。 以上述方式一的形式查看线程:1)同一进程中的线程是平等的,没有父子之分。当然也包括所谓的主线程、在主线程中创建的线程、在所谓的子线程中创建的线程。线程既然是平等的,只要进程不退出,倘若son线程退出,我们看到不会影响到孙线程的运行。2)孙线程在子线程中创建,可以理解为,启动孙线程的顺序点是在此时,而并非在主线程中。也就是说,我们可以在任意我们需要创建一个平行任务的地方,创建一个子线程,而并非得在主线程中创建。3)线程函数,其实,

modi000的博客 3070

[线程]等待一个线程, 获取当前线程引用,休眠当前线程, 线程的六种状态

我们知道, 多个线程的调度顺序是无序的, 谁先被调度不确定, 谁先结束也不确定, 所以我们引入线程等待, 可以控制线程结束的先后顺序 上述代码的thread 和 main 之间的结束顺序是不确定的如果我们希望让代码中的t先结束, main后结束, 就可以在main中使用线程等待join(join也要抛异常, 和sleep抛出的异常相同) 我们先修改一下代码, 让thread打印六次, main打印三次, 此时一定是main先结束, 再打印几次thread后, thread才结束 接下来我们加入join 注

m0_73992740的博客 1231

线程、线程池

目录进程进程的三种基本状态线程进程、线程的区别线程的6种状态线程的生命周期线程的2种创建方式线程常用方法线程协作线程死锁线程池并行、并发为什么不使用多进程而是使用多线程?   进程 进程是是应用程序运行的载体,是程序的一次执行过程,是临时的、有生命周期的,由程序、数据和进程控制块三部分组成,进程之间相互独立。   进程的三种基本状态 就绪(ready)状态:进程准备就绪,获得CPU时间片后可立即运行。就绪的进行放在就绪队列中,操作系统按指定的调度策略分配cpu时间片。 运行(runni

chy-x 的博客 1942

java线程池:线程池怎么开启的、线程池怎么工作的、线程池是怎么关闭的

1.序 位于 java.util.concurrent 下的 ThreadPoolExecutor 是java的线程池,可以用来管理线程。 本文围绕线程池的开启、工作、关闭三个方向进行探究,去追溯源码的实现。 2.线程池怎么开启的 ThreadPoolExecutor 有四个构造方法,如下: public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime, TimeUnit unit, B.

Yuwen_forJava的博客 3790

什么是后台线程?线程是否存活?线程的中断、join() 等待线程 以及 线程状态 等等干货

通过代码可以看到,想要休眠1000 毫秒,却休眠了1005秒,因为:系统会按照1000这个时间来控制线程的睡眠,等达到1秒后,就会唤醒线程,就会使线程从阻塞状态转化为就绪状态,但是呢,当线程转换为就绪状态后,并不是说就会直接去CPU上执行,这中间会有一个“调度开销”,所以,在时间上,就会和我们预期的不一样。在上述代码中,因为sleep() 的原因,所以抛出了异常,当Thread发出中断信号时,正在处于休眠的线程就会被强制唤醒,唤醒之后,sleep() 就会抛出异常,但是线程并没有终止,而是继续执行;

Shine0115的博客 1256
上一篇: 并发编程
下一篇: 进程
可爱软萌喵酱
博客等级 码龄5年 100粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值