如何在子线程中访问父线程的空间

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在子线程中访问父线程的空间相关的知识,希望对你有一定的参考价值。

在窗体上创建的空间Label lab = new Label();(隶属于父线程),如何在子线程对这个控件进行操作,将这个空间加入这个窗体中。如果使用Control.CheckForIllegalCrossThreadCalls = false;忽略控件的线程交叉引用错误的方法试过,不可取。那么我需要使用委托,但是对于委托我也不太了解,请用这个题目为例来具体讲解下委托的定义,还有委托所适用的场合,委托的优点。

首先要指出这里的父线程不是主线程 这的确是个问题,也就是说怎么才能保证父线程结束后其子线程也都退出.有人说在父线程结束前结束掉子线程不就行了吗?但事实是,如何父线程被暴力时,根本无法正确处理子线程.个人认为有两种方法. 一是在父线程中得到句柄,创建子线程时作为参数传给子线程,这样子线程通过这个句柄可以知道父线程是否仍存活,如何已结束,则结束自身. 父线程中:HANDLE hParent=INVALID_HANDLE_VALUE;
if (!DuplicateHandle (GetCurrentProcess (),GetCurrentThread (),GetCurrentProcess (),&hParent,NULL,TRUE,DUPLICATE_SAME_ACCESS))
printf ("get parent handle failed!\\n");

CreateThread (&sa,0,thread_fun2,(LPVOID)hParent,NULL,NULL);子线程中:HANDLE hParent=(HANDLE)lpParam;
DWORD nCode;
do

if (!GetExitCodeThread (hParent,&nCode))

printf ("get exit code failed!\\n");
printf ("error:%d\\n",GetLastError ());

if (nCode!=STILL_ACTIVE)//父线程结束
return 1;
....
while (....); 注意DuplicateHandle的参数,开始我图省事将最后一个参数也设为NULL,结果在子线程中调用GetExitCodeThread时会出错,通过错误代码知道是"拒绝访问",也即没有足够权限,因此在得到父线程实句柄时一定要指定访问权限. 第一种其实有点应付的味道,性能不好,而且并不能算是完成了要求,当然以实时性要求不高时也可以.另一种方法是通过一个全局数组,或者一个创建父线程时作为参数传入的数组存储所有建立的子线程句柄.这样当要结束父线程时,就可以根据这个数组将所有记录的子线程结束.有点浪费空间,不过性能肯定比第一种好,而且实时性也要好得多.
参考技术A CreateThread (&sa,0,thread_fun2,(LPVOID)hParent,NULL,NULL); 子线程中:HANDLE hParent=(HANDLE)lpParam;
DWORD nCode;
do

if (!GetExitCodeThread (hParent,&nCode))

printf ("get exit code failed!\n");
printf ("error:%d\n",GetLastError ());

if (nCode!=STILL_ACTIVE)//父线程结束

进程通信和线程通信

进程通信和线程通信

进程间通信:

  进程是拥有独立空间的,如果开多个进程对某个数据进行处理,由于进程是独立空间,那么两个进程如何通信拥有共同

空间呢?我们可以在父进程里启动一个服务器进程开辟一个公共空间。开启之后在子进程处理数据,父进程也会出现相应的

效果。Manager 是专门用来做共享的!

 1 from multiprocessing import Process, Manager
 2 mgr = Manager()
 3 d = mgr.dict()
 4 def func(d):
 5     d[a] = a
 6     print(d)
 7 p = Process(target=func, args=(d,))
 8 p.start()
 9 p.join()
10 print(d)
11 # 运行结果:
12 {a: a}
13 {a: a}

  使用Manager之后会失效资源共享,那么出现资源竞争怎么办?(参照线程资源竞争)我们可以使用队列,它默认使用了

锁的功能!使用会非常方便。

 1 from multiprocessing import Process, Queue
 2 q = Queue()
 3 q.put(1)
 4 
 5 
 6 def func(q):
 7     print(q.get())
 8     q.put(2)
 9 
10 
11 p = Process(target=func, args=(q,))
12 p.start()
13 p.join()
14 print(q.get())
15 # 返回结果:(表明队列是共有资源,可以共享)
16 1
17 2

  如果直接用  import queue  发现资源并没有共享!

 

线程间通信:

  线程间是共享空间的,每个线程对数据的修改都会起作用。如果两个线程同时修改,那么如果线程一还没有修改完,线程

二就开始修改,这样就会出问题,这个时候就需要线程锁来解决,类似于数据库里的原子操作(最小的操作单元,必须执行完才

能执行其他的)。

 1 from threading import Thread
 2 a = 0
 3 n = 10000000
 4 def incr(n):
 5     global a
 6     for i in range(n):
 7         a += 1
 8 def dncr(n):
 9     global a
10     for i in range(n):
11         a -= 1
12 t1 = Thread(target=incr, args=(n,))
13 t2 = Thread(target=dncr, args=(n,))
14 t1.start()
15 t2.start()
16 t1.join()
17 t2.join()
18 print(a)
19 # 运行多次的结果:
20 -288397    -122765    -1761997

  可以看出上面的代码出现了资源竞争的情况导致错误执行,我们使用锁来控制资源共享:

 1 from threading import Thread, Lock
 2 
 3 a = 0
 4 n = 10000000
 5 lock = Lock()  # 创建一把锁
 6 
 7 def incr(n):
 8     global a
 9     for i in range(n):
10         lock.acquire()  # 获取一把锁
11         a += 1
12         lock.release()  # 释放锁
13 
14 
15 def dncr(n):
16     global a
17     for i in range(n):
18         lock.acquire()  # 获取一把锁
19         a -= 1
20         lock.release()  # 释放锁
21 
22 
23 t1 = Thread(target=incr, args=(n,))
24 t2 = Thread(target=dncr, args=(n,))
25 t1.start()
26 t2.start()
27 t1.join()
28 t2.join()
29 print(a)

  创建锁也可以使用with lock:  部分代码如下:运行结果都为0:

1 def incr(n):
2     global a
3     for i in range(n):
4         with lock:
5             a += 1

 

消费者模式和生产者模式:

  生产者只关心队列是否已经满了,没有就生产,往队列里添加

  消费者只关心队列是否为空,为空就阻塞

 1 import threading
 2 import random
 3 import queue
 4 
 5 
 6 class Producer(threading.Thread):
 7 
 8     def __init__(self, queue):
 9         super().__init__()
10         self.queue = queue
11 
12     def run(self):
13         for i in range(10):
14             r = random.randint(0, 9)
15             if self.queue.qsize() < 3:
16                 self.queue.put(r)
17                 print(往队列里添加一个数据{}.format(r))
18 
19 
20 class Consumer(threading.Thread):
21 
22     def __init__(self, queue):
23         super().__init__()
24         self.queue = queue
25 
26     def run(self):
27         for i in range(10):
28             r = random.randint(0, 9)
29             if self.queue.empty():
30                 data = self.queue.get()
31                 print(从队列里get一个数据{}.format(data))
32 
33 
34 if __name__ == __main__:
35     q = queue.Queue()
36     p1 = Producer(q)
37     c1 = Consumer(q)
38     p1.start()
39     c1.start()
40     p1.join()
41     c1.join()
42     q.join()

  这里代码会阻塞,因为我们无法知道两个线程谁先执行,是没有规律的,线程p1几乎是瞬间将循环执行完,所以线程p1

只put了3个数据进去。线程c1在get数据的时候也只能取3个了,然后队列为空,会进去阻塞状态!可以对代码进行改进:

 1 import threading
 2 import random
 3 import queue
 4 import time
 5 
 6 
 7 class Producer(threading.Thread):
 8 
 9     def __init__(self, queue):
10         super().__init__()
11         self.queue = queue
12 
13     def run(self):
14         while True:
15             r = random.randint(0, 9)
16             if not self.queue.full():
17                 self.queue.put(r)
18                 print(往队列里添加一个数据{}.format(r))
19                 time.sleep(1)
20             else:
21                 print(队列满了)
22 
23 
24 class Consumer(threading.Thread):
25 
26     def __init__(self, queue):
27         super().__init__()
28         self.queue = queue
29 
30     def run(self):
31         while True:
32             data = self.queue.get()
33             print(从队列里get一个数据{}.format(data))
34             time.sleep(1)
35 
36 
37 if __name__ == __main__:
38     q = queue.Queue(5)
39     p1 = Producer(q)
40     c1 = Consumer(q)
41     p1.start()
42     c1.start()
43     p1.join()
44     c1.join()
45     q.join()
46 
47 # 代码运行结果:
48 往队列里添加一个数据4
49 从队列里get一个数据4
50 往队列里添加一个数据9
51 从队列里get一个数据9
52 ^CTraceback (most recent call last):
53   File "/home/pyvip/tz_spider/通信/xianchengtongxin.py", line 73, in <module>
54     p1.join()
55   File "/usr/lib/python3.5/threading.py", line 1054, in join
56     self._wait_for_tstate_lock()
57   File "/usr/lib/python3.5/threading.py", line 1070, in _wait_for_tstate_lock
58     elif lock.acquire(block, timeout):
59 KeyboardInterrupt
60 往队列里添加一个数据3
61 从队列里get一个数据3
62 往队列里添加一个数据7
63 从队列里get一个数据7
64 往队列里添加一个数据9
65 从队列里get一个数据9
66 往队列里添加一个数据9
67 从队列里get一个数据9
68 往队列里添加一个数据4
69 从队列里get一个数据4
70 
71 Process finished with exit code -1

  上面的代码是会一直运行的,这里是手动停止的结果!

 

以上是关于如何在子线程中访问父线程的空间的主要内容,如果未能解决你的问题,请参考以下文章

进程通信和线程通信

线程锁(互斥锁Mutex)

C# 子线程 传值

Android编程:如何在子线程中更新TextView控件

C++怎么在主线程中使用子线程的数据? 比如说主线程中有一个数组,如何在子线程中调用这个数组

QT中想在子线程中创建对话窗口怎么建