多线程编程

1、

当一个程序启动时,就有一个进程被操作系统(OS)创建,与此同时一个线程也立刻运行,该线程通常叫做程序的主线程(Main Thread),因为它是程序开始时就执行的,如果你需要再创建线程,那么创建的线程就是这个主线程的子线程。每个进程至少都有一个主线程,在Winform中,应该就是创建GUI的线程。

主线程的重要性体现在两方面:1.是产生其他子线程的线程;2.通常它必须最后完成执行比如执行各种关闭动作。

实验代码:

import threading
def f(i):
    print("I am from a thread,num=%d\n"%(i));
def main():
    for i in range(1,10):
        t=threading.Thread(target=f,args=(i,));#TypeError: f() argument after * must be a sequence, not int
        t.setDaemon(True);
        t.start();
if __name__=="__main__":
    main();

实验结果为:


结论:虽然线程的创建和启动是有顺序的,但线程是并发运行的,所以那个线程先执行完是不确定的。从运行结果可以看到,输出的数字也是没有规律的。而且在“I am from a thread, num=4",前面还有个>>>,是说明主程序在此处已经退出。

线程对象的setDaemon()方法可以让子线程随着主线程的退出而结束,不过注意的是setDaemon()方法必须在线程对象没有调用start()方法之前调用(默认情况下;在python

中,主线程结束后,会默认等待子线程结束后,主线程才退出)。

2、阻塞进程

# -*- coding: cp936 -*-
import threading
def f(i):
    print("I am from a thread,num=%d\n"%(i));
def main():
    for i in range(1,10):
        t=threading.Thread(target=f,args=(i,));#TypeError: f() argument after * must be a sequence, not int
        t.setDaemon(True);
        t.start();
    t.join();#可以阻塞进程直到线程执行完毕。
if __name__=="__main__":
    main();
运行结果为:


可以看到,进程在所有线程结束后才退出。

3、指令锁

当多个线程同时访问同一资源(比如,全局变量),可能会出现访问冲突。

冲突:

import threading
import time
num=0;
def f():
    global num;
    b=num;
    time.sleep(0.0001);
    num=b+1;
    print('%s\n'%threading.currentThread().getName());
def main():
    for i in range(1,20):
        t=threading.Thread(target=f);
        t.setDaemon(True);
        t.start();
    t.join();
    print(num);
if __name__=="__main__":
    main();

实验结果为:


改进:

可以使用锁来限制线程同时访问同一资源。指令锁处于锁定状态时,不能被特定的线程所拥有。当线程申请一个处于锁定状态的锁时线程会被阻塞,直至该锁被释放。

在访问全局变量之前申请一个指令锁,在访问全局变量之后释放一个指令锁,这样就可以避免多个线程同时访问全局变量。

# -*- coding: cp936 -*-
import threading
import time
lock=threading.Lock();#创建一个指令锁
num=0;
def f():
    global num;
    if lock.acquire():
        print('%s获得指令锁.'%threading.currentThread().getName());
        b=num;
        time.sleep(0.0001);
        num=b+1;
        lock.release()#释放指令锁
        print('%s释放指令锁.'%threading.currentThread().getName());
    print('%s\n'%threading.currentThread().getName());
def main():
    for i in range(1,20):
        t=threading.Thread(target=f);
        t.setDaemon(True);
        t.start();
    t.join();
    print(num);
if __name__=="__main__":
    main();
实验结果:



4、可重入锁

使用指令锁可以避免多个线程同时访问全局变量。但是如果一个线程里面有递归函数,则它可能会多次请求访问全局变量,此时,即使线程已经获得指令锁,在它再次申请

指令锁时会被阻塞。每个可重入锁都关联一个请求计数器和一个占有它的线程,当请求计数器为0时,这个锁可以被一个线程请求得到并把锁的请求计数加1。如果同一个线程

再次请求这个锁,请求计数器就会增加,当该线程释放RLock时,其计数器减1,当计数器为0时,该锁被释放。

实验代码:

# -*- coding: cp936 -*-
import threading
import time
lock=threading.RLock();#创建一个可重入锁
num=0;
def f():
    global num;
    #第一次请求锁定
    if lock.acquire():
        print('%s获得指令锁.'%threading.currentThread().getName());
        time.sleep(0.0001);
        #第二次请求锁定
        if lock.acquire():
            print('%s获得指令锁.'%threading.currentThread().getName());
            time.sleep(0.0001);
            lock.release()#释放指令锁
            print('%s释放指令锁.'%threading.currentThread().getName());
    time.sleep(0.0001);  
    print('%s释放指令锁.'%threading.currentThread().getName());
    lock.release()#释放指令锁
def main():
    for i in range(1,20):
        t=threading.Thread(target=f);
        t.setDaemon(True);
        t.start();
    t.join();
    print(num);
if __name__=="__main__":
    main();

实验结果:

>>> 
Thread-1获得指令锁.
Thread-1获得指令锁.
Thread-1释放指令锁.
Thread-1释放指令锁.
Thread-2获得指令锁.
Thread-2获得指令锁.
Thread-2释放指令锁.
Thread-2释放指令锁.
Thread-3获得指令锁.
Thread-3获得指令锁.
Thread-3释放指令锁.
Thread-3释放指令锁.
Thread-4获得指令锁.
Thread-4获得指令锁.
Thread-4释放指令锁.
Thread-4释放指令锁.
Thread-5获得指令锁.
Thread-5获得指令锁.
Thread-5释放指令锁.
Thread-5释放指令锁.
Thread-6获得指令锁.
Thread-6获得指令锁.
Thread-6释放指令锁.
Thread-6释放指令锁.
Thread-7获得指令锁.
Thread-7获得指令锁.
Thread-7释放指令锁.
Thread-7释放指令锁.
Thread-8获得指令锁.
Thread-8获得指令锁.
Thread-8释放指令锁.
Thread-8释放指令锁.
Thread-9获得指令锁.
Thread-9获得指令锁.
Thread-9释放指令锁.
Thread-9释放指令锁.
Thread-10获得指令锁.
Thread-10获得指令锁.
Thread-10释放指令锁.
Thread-10释放指令锁.
Thread-11获得指令锁.
Thread-11获得指令锁.
Thread-11释放指令锁.
Thread-11释放指令锁.
Thread-12获得指令锁.
Thread-12获得指令锁.
Thread-12释放指令锁.
Thread-12释放指令锁.
Thread-13获得指令锁.
Thread-13获得指令锁.
Thread-13释放指令锁.
Thread-13释放指令锁.
Thread-14获得指令锁.
Thread-14获得指令锁.
Thread-14释放指令锁.
Thread-14释放指令锁.
Thread-15获得指令锁.
Thread-15获得指令锁.
Thread-15释放指令锁.
Thread-15释放指令锁.
Thread-16获得指令锁.
Thread-16获得指令锁.
Thread-16释放指令锁.
Thread-16释放指令锁.
Thread-17获得指令锁.
Thread-17获得指令锁.
Thread-17释放指令锁.
Thread-17释放指令锁.
Thread-18获得指令锁.
Thread-18获得指令锁.
Thread-18释放指令锁.
Thread-18释放指令锁.
Thread-19获得指令锁.
Thread-19获得指令锁.
Thread-19释放指令锁.
Thread-19释放指令锁.
0
>>> 

5、信号量


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值