'''
在Python中,可以通过继承threading.Thread类来创建线程。通过继承threading模块中Thread类来
创建新类,在新类中重写run方法,然后就可以通过start方法启动线程。线程启动后将
运行run方法。以下代码是使用threading模块创建线程。
'''
# coding:utf-8
# Python Bible - e23_1_1.py
import threading							#导入threading模块
class mythread(threading.Thread):			#通过继承Thread创建类
	def __init__(self, num):				#定义初始化方法
		threading.Thread.__init__(self)		#调用父类的初始化方法
		self.num = num
	def run(self):							#重载run方法
		print('I am ', self.num)

t1 = mythread(1)							#生成mythread对象
t2 = mythread(2)							#生成mythread对象
t3 = mythread(3)							#生成mythread对象
t1.start();									#运行线程1,实际上是运行run方法
t2.start();									#运行线程2
t3.start();									#运行线程3
'''
D:\CODE\PYTHON\Python_Bao3Dian3>python e23_1_1.py
I am  1
I am  2
I am  3
'''

 

'''
除了通过继承threading.Thread创建类以外,还可以通过使用thread.Thread直接在线程中
运行函数。以下代码是使用threading.Thread直接创建线程。
'''
# encoding: UTF-8
# in Python 3.2.5
import threading									# 导入threading 模块
def run(x,y):										# 定义 run 函数
	for i in range(x,y):
		print(i)

t1 = threading.Thread(target = run, args = (15,20))	# 直接使用 Thread 附加函数, args 为函数参数
t1.start()											# 运行线程

t2 = threading.Thread(target = run, args = (7,11))	# 直接使用 Thread 附加函数, args 为函数参数
t2.start()											# 运行线程
'''
D:\CODE\PYTHON\Python_Bao3Dian3>python e23_1_1b.py
15
7
16
8
17
18
9
19
10
'''

 

# coding:UTF-8
# 23.1.2 Thread对象中的方法
'''
1. join()方法
如果一个线程或函数在执行过程中调用另一个线程, 并且必须等待后一线程完成操作后才能
继续当前线程的执行, 那么在调用线程中可以使用被调用线程的join()方法.join()方法的原型如下.
join([timeout])
	timeout 可选参数, 单位为秒, 是线程运行的最长时间
'''
import threading						# 导入threading模块
import time								# 导入 time 模块
class Mythread(threading.Thread):		# 通过继承Thread创建类
	def __init__(self,id):				# 初始化方法
		threading.Thread.__init__(self)	# 调用父类的初始化方法
		self.id = id
	def run(self):						# 重写run方法
		x = 0
		time.sleep(3)					# 使用time模块中的sleep()方法让线程休眠3秒
		print(self.id)
		
def func1():							# 定义函数
	t.start()							# 运行线程
	#t.join()
	for i in range(5):
		print(i)
			
t = Mythread(182)						
func1()									
'''
# 到最后才有线程的输出, func1函数没有等待线程完成
D:\CODE\PYTHON\Python_Bao3Dian3>python e23_1_2a.py
0
1
2
3
4
182

# 把 t.join() 前的 # 去掉, 再次运行脚本。线程休眠3秒输出182,然后再输出0-4
D:\CODE\PYTHON\Python_Bao3Dian3>python e23_1_2a.py
182
0
1
2
3
4
'''

 

# coding:UTF-8
# 23.1.2 Thread对象中的方法
'''
2. isAlive()方法
当线程创建后,可以使用Thread对象的isAlive方法查看线程是否运行。以下代码时使用Thread
对象的isAlive方法查看线程是否运行。
'''
import threading						# 导入threading模块
import time								# 导入time模块
class mythread(threading.Thread):		# 通过继承Thread创建类
	def __init__(self,id):				# 初始化方法
		threading.Thread.__init__(self)	# 调用父类的初始化方法
		self.id = id
	def run(self):						# 重写run方法
		time.sleep(5)
		print(self.id)
		
t = mythread(1)							# 生成mythread对象
def func():								# 定义函数
	t.start()							# 运行/启动线程
	print('isAlive:%s' % t.isAlive())	# 打印线程状态
	
func()									# 调用函数
'''
D:\CODE\PYTHON\Python_Bao3Dian3>python e23_1_2b.py
isAlive:True							# 从函数输出的线程状态
1										# 线程输出
'''

 

# coding:UTF-8
# 23.1.2 Thread对象中的方法
'''
3. 线程名
线程名可以在类的初始化函数中定义,也可以使用Thread对象的setName方法设置。
使用Thread对象的getName方法可以获得线程名。
'''
import threading											# 导入threading模块
class mythread(threading.Thread):							# 通过继承Thread创建类
	def __init__(self,threadname):
		threading.Thread.__init__(self,name = threadname)	# 初始化线程名
	def run(self):											# 重写run方法
		print(self.getName())
		
t1 = mythread('t1')											# 类实例化,设置线程名
print(t1.getName())											# 调用getName方法获得线程名

t1.setName('T')												# 调用setNa方法设置线程名
print(t1.getName())

t2 = mythread('t2')
t2.start()

print(t2.getName())
t2.setName('TT')
print(t2.getName())
'''
D:\CODE\PYTHON\Python_Bao3Dian3>python e23_1_2c.py
t1
T
t2
t2
TT
'''

 

# -*- coding:utf-8 -*-
# file: threaddaemon.py
# 23.1.2 Thread对象中的方法
'''
4. daemon属性
在脚本运行过程中,如果主线程创建一个子线程,则当主线程退出时,会检验
子线程是否完成。如果子线程未完成,则主线程会等待子线程完成后再退出。如果想要主线程退出
时,不管子线程是否完成都随主线程退出,则可以通过设置Thread对象的daemon属性为True
来达到这种效果。以下代码是给Thread对象的daemon属性赋值为True,设置子线程随主线程结束而结束。
'''
import threading											# 导入threading模块
import time
class mythread(threading.Thread):
	def __init__(self,threadname):
		threading.Thread.__init__(self,name = threadname)
		self.sleeptime = 2
	def run(self):
		time.sleep(self.sleeptime)
		print(self.getName())
	def setSleeptime(self, time):
		self.sleeptime = time

t1 = mythread('t1')
t2 = mythread('t2')
print('t1.daemon is %s' % t1.daemon )
t2.setSleeptime(10)
t2.daemon = True
def func1():
	t1.start()
	print('func1 done')
def func2():
	t2.start()
	print('func2 done')

func1()
func2()
'''
D:\CODE\PYTHON\Python_Bao3Dian3>python e23_1_2d.py
t1.daemon is False
func1 done
func2 done
t1
'''

 

'''
A boolean value indicating whether this thread is a daemon thread (True) or not (False). 
This must be set before start() is called, otherwise RuntimeError is raised. 
Its initial value is inherited from the creating thread; the main thread is not 
a daemon thread and therefore all threads created in the main thread default to 
daemon = False.

The entire Python program exits when no alive non-daemon threads are left.

当daemon被设置为True时,如果主线程退出,那么子线程也将跟着退出,

反之,子线程将继续运行,直到正常退出。
'''
import threading
import time

class myThread(threading.Thread):
   def __init__(self, threadname):
     threading.Thread.__init__(self, name=threadname)
     self.sleeptime = 2 

   def run(self):
     time.sleep(self.sleeptime)
     print(self.getName())
   def setSleeptime(self, t): 
     self.sleeptime = t 

def fun1():
   t1.start()
   print("fun1 done")

def fun2():
   t2.start()
   print("fun2 done")

t1=myThread("t1")
t2=myThread("t2")
t2.setSleeptime(10);
t2.setDaemon(True)
fun1()
fun2()
print("now u will see me")
'''
D:\CODE\PYTHON\Python_Bao3Dian3>python tt.py
fun1 done
fun2 done
now u will see me
t1
'''

 

# -*- coding:utf-8 -*-
# file: syn.py
# 23.2 线程同步
'''
23.2.1 简单的线程同步
使用Thread对象的Lock和RLock可以实现简单的线程同步. 如果某个数据在某一时刻只允许一个线程进行操作,则可以
将操作过程放在acquire方法和release方法之间.

'''
import threading											# 导入threading模块
import time
class mythread(threading.Thread):
	def __init__(self,threadname):
		threading.Thread.__init__(self,name = threadname)
	def run(self):
		global x
		#lock.acquire()
		for i in range(3):
			x += 1
		time.sleep(2)
		print(x)
		#lock.release()
	
#lock = threading.RLock()
t1 = []
for i in range(3):
	t = mythread(str(i))
	t1.append(t)
x = 0
for i in t1:
	i.start()
'''
D:\CODE\PYTHON\Python_Bao3Dian3>python e23_2_1a.py
3
6
9

D:\CODE\PYTHON\Python_Bao3Dian3>python e23_2_1a.py
9
9
9
'''

 

# -*- coding:utf-8 -*-
# 23.2 线程同步
# P_C.py
'''
23.2.2 使用条件变量保持线程同步
Python的Condition对象提供了对复杂线程同步的支持. 使用Condition对象可以在某些事件
触发后在处理数据. Condition对象除了具有acquire方法和release方法外, 还有wait方法, notify方法,
notifyAll方法等用于条件处理的方法. 下面的P_C.py是使用Condition对象来实现著名的
生产者和消费者的关系.

'''
import threading											# 导入threading模块
class Producer(threading.Thread):							# 定义生产者类
	def __init__(self,threadname):
		threading.Thread.__init__(self,name = threadname)
	def run(self):
		global x
		con.acquire()										# 调用con的acquire方法
		if x == 1000000:
			con.wait()										# 调用con的wait方法
			#pass
		else:
			for i in range(1000000):
				x = x + 1
			con.notify()									# 调用con的notify方法
		print(x)
		con.release()										# 调用con的release方法
class Consumer(threading.Thread):							# 定义生产者类
	def __init__(self,threadname):
		threading.Thread.__init__(self,name = threadname)
	def run(self):
		global x
		con.acquire()
		if x == 0:
			con.wait()
			#pass
		else:
			for i in range(1000000):
				x = x -1
			con.notify()
		print(x)
		con.release()

con = threading.Condition()									# 生成Condition对象
x = 0
p = Producer('Producer')									# 生成生产者对象
c = Consumer('Consumer')									# 生成消费者对象
p.start()
c.start()
p.join()													# 等待p线程结束
c.join()
print(x)
'''
D:\CODE\PYTHON\Python_Bao3Dian3>python e23_2_2a.py
1000000
0
0
# 把使用Condition对象的语句删除. 运行修改后的脚本, 输出如下(每次输出可能不同)
D:\Python27>python D:\CODE\PYTHON\Python_Bao3Dian3\ttb.py
-29904
895935
895935
'''

 

import threading
import time

class Producer(threading.Thread):
    def run(self):
        global count
        while True:
            if con.acquire():
                if count > 1000:
                    con.wait()
                else:
                    count = count+100
                    msg = self.name+' produce 100, count=' + str(count)
                    print(msg)
                    con.notify()
                con.release()
                time.sleep(1)

class Consumer(threading.Thread):
    def run(self):
        global count
        while True:
            if con.acquire():
                if count < 100:
                    con.wait()
                else:
                    count = count-3
                    msg = self.name+' consume 3, count='+str(count)
                    print(msg)
                    con.notify()
                con.release()
                time.sleep(1)

count = 500
con = threading.Condition()

def test():
    for i in range(2):
        p = Producer()
        p.start()
    for i in range(5):
        c = Consumer()
        c.start()
if __name__ == '__main__':
    test()