不同线程之间向对方的窗口发送消息

    第二次阅读了Jeffrey Richter先生的<<windows核心编程>>窗口消息部分后,写了篇读书笔记,相同诸位共享,其中有一些不太明白的地方,望各位指出。下面是正文。

  如果A线程向B线程创建的窗口发送消息,无论AB线程是否同处于同一个进程,都采用相同的处理方式。

  如果AB线程处于不同的进程,A线程不可能处理B线程的窗口消息,因为发送线程不是运行在接收进程的地址空间中,因此不能访问相应窗口过程的代码和数据。

  如果AB线程处于相同的进程呢?此时A线程虽然可以访问B线程的窗口过程的,也可以调用某些窗口过程,但这样就不是通过发送消息种方法了。对于B线程的窗口,它只能从B线程的消息队列中获取消息,B线程窗口的处理过程可以在A线程中,但是消息却必须从B的消息队列中获取。我这样理解是否正确?

A线程向B线程创建的窗口发送消息时,处理方式如下:

  第一, 发送的消息要追加到B线程的发送消息队列(send-message queue),同时会为B线程设定QS_SENDMESSAGE标志。

  第二,B线程将有两种行为:

  a) B线程正执行代码,没有等待消息,则发送的消息不会立即被处理,系统不能中断线程来立即处理该消息(这意味着系统强壮,线程之间不会相互影响对方)

  b) B线程正等待消息,此时系统会检查B线程的唤醒标志,如果检查到唤醒标志含有QS_SENDMESSAGE,则会从B线程的发送消息队列中取出第一个消息(可能有多个,可能有多个线程同时向B线程发送了消息),然后唤醒B线程处理该消息,直到处理完所以的消息。然后关闭QS_SENDMESSAGE标志,挂起。

 第三 A线程发送消息后(使用SendMessage),它有两种行为:

  a) 处于挂起状态(即不会立即从SendMessage函数中返回)A线程会等待一个消息出现在它的应答消息队列中。这是由OS来做的,在B线程处理完A线程发送给它的窗口的消息后,该窗口过程的返回值会被OS登记到A线程的消息队列,相应标志位被设置,然后A线程被唤醒,从应答消息队列中取出该返回值,作为SendMessage的返回值返回给A线程。

  b) 当A处于挂起状态时,C线程向A线程的窗口发送一个消息,则系统要立即处理发送的消息。在这种情况下,系统不必等待线程去调用GetMessage、PeekMessage或WaitMessage。是系统处理该发送消息还是A线程的窗口处理过程处理该发送消息?如果是后者,这是否意味着发送消息处理完毕后A线程又被挂起?A线程会被唤醒么?
 未完,待续。
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于UDP协议的Python多线程在线聊天程序的代码,具备图形化界面和托盘功能,能够在不同主机之间发送和接收文本信息,同时能够从输入框中获取IP和端口号信息: ```python import threading import socket import tkinter as tk import tkinter.scrolledtext as st import tkinter.messagebox as mb from tkinter import ttk # 定义全局变量 local_ip = '127.0.0.1' local_port = 8888 target_ip = '' target_port = '' sock = None t_recv = None t_send = None # 接收消息 def recv_msg(): global sock while True: try: data, addr = sock.recvfrom(1024) msg = f'{addr[0]}:{addr[1]} >> {data.decode()}' text.insert(tk.END, msg + '\n') except ConnectionResetError: mb.showinfo('提示', '对方已经关闭连接!') break # 发送消息 def send_msg(): global sock global target_ip global target_port while True: try: msg = input_text.get() if not msg: continue sock.sendto(msg.encode(), (target_ip, target_port)) input_text.set('') except ConnectionResetError: mb.showinfo('提示', '对方已经关闭连接!') break # 启动接收线程发送线程 def start_chat(): global sock global t_recv global t_send if not target_ip or not target_port: mb.showinfo('提示', '请输入对方的IP地址和端口号!') return # 创建UDP套接字 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((local_ip, local_port)) # 启动接收和发送线程 t_recv = threading.Thread(target=recv_msg) t_send = threading.Thread(target=send_msg) t_recv.start() t_send.start() # 关闭聊天 def close_chat(): global sock global t_recv global t_send if t_recv and t_recv.is_alive(): t_recv.join() if t_send and t_send.is_alive(): t_send.join() if sock: sock.close() # 创建主窗口 root = tk.Tk() root.title('UDP聊天') root.geometry('400x300') # 创建菜单栏 menubar = tk.Menu(root) root.config(menu=menubar) # 创建文件菜单 filemenu = tk.Menu(menubar, tearoff=False) menubar.add_cascade(label='文件', menu=filemenu) filemenu.add_command(label='退出', command=root.quit) # 创建帮助菜单 helpmenu = tk.Menu(menubar, tearoff=False) menubar.add_cascade(label='帮助', menu=helpmenu) helpmenu.add_command(label='关于', command=lambda: mb.showinfo('关于', 'UDP聊天 V1.0')) # 创建输入框和发送按钮 input_text = tk.StringVar() input_frame = ttk.Frame(root) input_frame.pack(side=tk.BOTTOM, fill=tk.X) input_entry = ttk.Entry(input_frame, textvariable=input_text) input_entry.pack(side=tk.LEFT, expand=True, fill=tk.X) input_entry.bind('<Return>', lambda event: send_msg()) send_button = ttk.Button(input_frame, text='发送', command=send_msg) send_button.pack(side=tk.RIGHT) # 创建聊天窗口 text = st.ScrolledText(root, wrap=tk.WORD) text.pack(expand=True, fill=tk.BOTH) # 创建IP地址和端口号输入框 ip_frame = ttk.Frame(root) ip_frame.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5) ip_label = ttk.Label(ip_frame, text='目标IP地址:') ip_label.pack(side=tk.LEFT) ip_entry = ttk.Entry(ip_frame) ip_entry.pack(side=tk.LEFT, expand=True, fill=tk.X) port_label = ttk.Label(ip_frame, text='目标端口号:') port_label.pack(side=tk.LEFT) port_entry = ttk.Entry(ip_frame) port_entry.pack(side=tk.LEFT) # 创建连接和关闭按钮 button_frame = ttk.Frame(root) button_frame.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5) connect_button = ttk.Button(button_frame, text='连接', command=start_chat) connect_button.pack(side=tk.LEFT) close_button = ttk.Button(button_frame, text='关闭', command=close_chat) close_button.pack(side=tk.LEFT) # 创建系统托盘 tray = None if 'win' in tk.Tk().windowingsystem.lower(): import ctypes ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID('UDPChat') root.iconbitmap('icon.ico') tray = tk.SystemTrayIcon(root, 'icon.ico', '') tray.visible = True root.mainloop() ``` 这个程序使用了Python的socket模块创建UDP套接字,使用多线程技术实现了接收和发送消息的功能,同时使用了tkinter模块创建了图形化界面,并且使用了托盘功能将程序最小化到系统托盘。用户可以通过输入框输入目标主机的IP地址和端口号,然后点击连接按钮启动聊天功能。当用户输入消息并点击发送按钮时,消息会通过UDP协议发送给目标主机。同时,程序会在图形化界面上显示接收到的消息。当用户关闭聊天时,程序会关闭UDP套接字和线程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值