MIT6.828_HW8_User-level threads

本文深入解析MIT6.828课程作业8中的用户级线程创建与切换实现。重点讲解了thread结构体及线程指针的位置理解,通过.S文件直接使用.c文件中的变量current_thread等实例,展示了如何在汇编语言中实现线程间的切换,包括保存和恢复栈指针、状态更新等关键步骤。

MIT6.828_HW8_User-level threads

uthread creates two threads and switches back and forth between them. Each thread prints “my thread …” and then yields to give the other thread a chance to run.

thread结构体以及线程指针位置的理解,是完成这个 HW 的关键。

struct thread {
  int        sp;                /* saved stack pointer */
  char stack[STACK_SIZE];       /* the thread's stack */
  int        state;             /* FREE, RUNNING, RUNNABLE */
};

线程结构体指针

经过LAB4的洗礼,在根据给出的提示,写出实现代码并不难。不过在实现过程发现,在 .S 文件中竟然可以直接使用 .c 文件中的变量current_thread等,而且在讲义中还特意强调uthread_switch.S ends with .S,这引起了我的好奇,毕竟一直都没有探究汇编的细节。

  • .s: 汇编语言源程序;汇编
    • 小写的s文件,在后期阶段不在进行预处理操作,所以我们不能在这里面写预处理的语句在里面
  • .S:汇编语言源程序;预处理,汇编
    • 大写的S文件,还会进行预处理、汇编等操作,所以我们可以在这里面加入预处理的命令
	.globl thread_switch
thread_switch:
	/* YOUR CODE HERE */
	// C语言函数调用会压入下一条语句的 eip.
	pushal
	// eax 指向 sp
	movl current_thread, %eax
	// save sp
	movl %esp, (%eax)

	
	movl next_thread, %eax
	movl %eax, current_thread
	// restore sp
	movl (%eax), %esp
	
	popal

	movl $0x0, next_thread

	// popal 后esp指向return address
	ret				/* pop return address from stack */



	/* pop return address from stack */

<think>我们在处理一个关于MySQL锁监控和性能模式(performance_schema)的查询需求。用户希望优化或解读一条从`performance_schema.data_locks`表查询锁信息及相关事务信息的SQL语句。根据提供的引用,我们有相关的表结构和查询示例。 引用中提到的关键表: 1. `data_locks`:当前的锁信息,包括锁的类型、模式和持有者。 2. `data_lock_waits`:锁等待信息,展示请求锁的事务和阻塞该请求的事务之间的关系。 3. `metadata_locks`:元数据锁信息。 另外,引用中还给出了几个常用的查询锁和事务的语句,例如: - 查询是否锁表:`show OPEN TABLES where In_use > 0;` - 查询进程:`show processlist` - 查看当前的事务:`SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;` - 查看当前锁定的事务:`SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;` (注意:在MySQL 8.0中,这个表已经移除了,改用performance_schema中的表) - 查看当前等锁的事务:`SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;` (同样,在8.0中已经移除,改用performance_schema) 现在,用户想要一条从`performance_schema.data_locks`表查询锁信息及相关事务信息的SQL语句。我们可能需要关联其他表(如`data_lock_waits`、`threads`、`processlist`等)来获取更完整的信息。 考虑到MySQL 8.0中,`INFORMATION_SCHEMA`中关于锁的表已经移除,我们使用performance_schema中的表。 设计查询语句时,我们可能需要以下信息: - 锁信息:来自`data_locks` - 事务信息:可以通过`data_locks`中的`ENGINE_TRANSACTION_ID`关联到事务(但注意,`data_locks`中的事务ID是InnoDB内部的事务ID,而`INNODB_TRX`表(在information_schema中)也有事务信息,但8.0中已经移除,我们可以通过`performance_schema.events_transactions_current`来获取事务信息?不过,实际上,我们可能更关心的是事务的线程、状态等。 另外,我们可能需要关联线程表(`performance_schema.threads`)来获取连接线程的信息,进而关联到`processlist`。 常见的查询锁以及持有锁和等待锁的会话的语句如下: 我们可以这样写: 1. 查询当前所有锁的信息,包括锁定的对象、锁的类型、锁的模式(共享、排他)、事务ID、线程ID等。 2. 同时,我们可能还想知道哪些锁被阻塞,以及阻塞的关系。 根据引用[4]中`metadata_locks`表的字段,我们可以类比`data_locks`表,但注意`data_locks`是存储引擎层的锁,而`metadata_locks`是元数据锁(表结构等)。 这里我们主要关注`data_locks`(存储引擎层的锁,如InnoDB的行锁)。 一个基本的查询锁信息的语句可能是: ```sql SELECT dl.engine_lock_id, dl.engine_transaction_id, dl.lock_type, dl.lock_mode, dl.lock_status, dl.lock_data, t.PROCESSLIST_ID AS connection_id, p.USER, p.HOST, p.DB, p.COMMAND, p.TIME, p.STATE, p.INFO FROM performance_schema.data_locks dl LEFT JOIN performance_schema.threads t ON dl.thread_id = t.thread_id LEFT JOIN information_schema.processlist p ON t.PROCESSLIST_ID = p.ID; ``` 但是,注意在MySQL 8.0中,`PROCESSLIST`表在`performance_schema`中也有(`performance_schema.processlist`),而且`information_schema.processlist`实际上是一个视图,其数据来源于`performance_schema.threads`。所以我们可以直接使用`performance_schema.threads`表来获取连接信息。 优化:我们可以直接从`threads`表中获取连接信息,而不必再连接`processlist`视图。因为`threads`表包含了`PROCESSLIST_USER`, `PROCESSLIST_HOST`, `PROCESSLIST_DB`等列。 改进后的查询: ```sql SELECT dl.engine_lock_id, dl.engine_transaction_id, dl.lock_type, dl.lock_mode, dl.lock_status, dl.lock_data, t.PROCESSLIST_ID AS connection_id, t.PROCESSLIST_USER AS user, t.PROCESSLIST_HOST AS host, t.PROCESSLIST_DB AS db, t.PROCESSLIST_COMMAND AS command, t.PROCESSLIST_TIME AS time, t.PROCESSLIST_STATE AS state, t.PROCESSLIST_INFO AS info FROM performance_schema.data_locks dl LEFT JOIN performance_schema.threads t ON dl.thread_id = t.thread_id; ``` 这个查询可以获取到当前所有的锁(存储引擎层)以及持有这些锁的线程(连接)信息。 如果我们还想查看锁等待关系,我们需要关联`data_lock_waits`表: ```sql SELECT r.engine_lock_id AS waiting_lock_id, w.engine_lock_id AS blocking_lock_id, r.engine_transaction_id AS waiting_transaction_id, w.engine_transaction_id AS blocking_transaction_id, tr.PROCESSLIST_ID AS waiting_connection_id, tb.PROCESSLIST_ID AS blocking_connection_id, tr.PROCESSLIST_INFO AS waiting_query, tb.PROCESSLIST_INFO AS blocking_query FROM performance_schema.data_lock_waits dlw INNER JOIN performance_schema.data_locks r ON dlw.requesting_engine_lock_id = r.engine_lock_id INNER JOIN performance_schema.data_locks w ON dlw.blocking_engine_lock_id = w.engine_lock_id INNER JOIN performance_schema.threads tr ON r.thread_id = tr.thread_id INNER JOIN performance_schema.threads tb ON w.thread_id = tb.thread_id; ``` 这个查询可以获取锁等待的详细信息,包括等待的锁和阻塞的锁,以及相关联的事务和连接信息。 针对用户的问题,如果用户想要一条查询锁信息及相关事务信息的语句,我们可以提供第一种查询(即查询所有锁及连接信息)。如果用户想要查看锁等待,则提供第二种。 但是,用户没有给出具体的SQL语句,所以我们只能根据需求构建。如果用户已经有一条SQL需要优化或解读,我们需要具体分析。但这里用户没有提供,所以我们可以给出一个通用的查询。 另外,引用[3]和[4]提到了`metadata_locks`表,如果用户需要元数据锁的信息,我们可以单独查询。 注意:要使用这些表,需要确保已经启用了performance_schema,并且启用了相关的instruments和consumers(例如:`wait/lock/metadata/sql/mdl` 和 `wait/lock/table/sql/handler` 等)。 因此,回答用户: 我们可以提供两条SQL语句: 1. 查询当前存储引擎层的锁信息以及持有锁的连接信息。 2. 查询锁等待关系。 另外,我们也可以提供查询元数据锁的语句,例如: ```sql SELECT OBJECT_TYPE, OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, OWNER_THREAD_ID, OWNER_EVENT_ID FROM performance_schema.metadata_locks; ``` 最后,关于优化:如果用户觉得查询performance_schema表太慢(因为数据量大),我们可以考虑: - 添加合适的过滤条件(例如,只查询某个数据库,或者某个连接等) - 定期收集或者只在需要时查询(因为这些表是实时变化的) 另外,注意performance_schema的表是内存表,查询时要注意性能影响。 由于用户没有提供具体的SQL语句,我们只能给出通用建议和查询示例。 下面,我们将按照用户要求的格式进行回答。 </think>### 优化与解读SQL查询:锁信息及相关事务分析 要优化或解读从`performance_schema.data_locks`表查询锁信息及相关事务的SQL语句,需结合性能模式(Performance Schema)的结构和锁机制原理。以下是关键点和优化建议: --- ### 1. **基础查询语句解读** ```sql SELECT * FROM performance_schema.data_locks WHERE LOCK_STATUS = 'WAITING'; -- 查找等待中的锁 ``` - **核心字段说明**: - `ENGINE_LOCK_ID`:锁的唯一标识 - `ENGINE_TRANSACTION_ID`:关联的事务ID(InnoDB内部事务ID) - `LOCK_TYPE`:锁类型(如`RECORD`行锁、`TABLE`表锁) - `LOCK_MODE`:锁模式(如`X`排他锁、`S`共享锁) - `LOCK_STATUS`:状态(`GRANTED`已持有、`WAITING`等待中) - `LOCK_DATA`:锁定数据(如主键值或行记录) --- ### 2. **关联事务信息的优化查询** 通过关联`threads`和`events_transactions_current`表,获取事务详情: ```sql SELECT dl.ENGINE_TRANSACTION_ID, dl.LOCK_TYPE, dl.LOCK_MODE, dl.LOCK_STATUS, t.PROCESSLIST_ID AS conn_id, -- 连接ID etc.STATE AS trx_state, -- 事务状态 etc.TIMER_WAIT/1e9 AS trx_duration_sec -- 事务持续时间 FROM performance_schema.data_locks dl LEFT JOIN performance_schema.threads t ON dl.THREAD_ID = t.THREAD_ID LEFT JOIN performance_schema.events_transactions_current etc ON dl.ENGINE_TRANSACTION_ID = etc.THREAD_ID WHERE dl.LOCK_STATUS = 'WAITING'; ``` #### **优化点**: 1. **精准定位阻塞源**: 通过`LOCK_STATUS='WAITING'`筛选被阻塞的锁,快速定位性能瓶颈。 2. **关联线程与事务**: `threads`表提供连接ID(`PROCESSLIST_ID`),可用于`KILL`阻塞会话[^2]。 3. **事务状态监控**: `events_transactions_current`展示事务状态(如`ACTIVE`、`COMMITTED`)和持续时间,识别长事务[^4]。 --- ### 3. **高级优化:锁等待链分析** 结合`data_lock_waits`表定位阻塞关系: ```sql SELECT r.ENGINE_TRANSACTION_ID AS waiting_trx_id, b.ENGINE_TRANSACTION_ID AS blocking_trx_id, r.LOCK_DATA AS locked_row, CONCAT('KILL ', bt.PROCESSLIST_ID) AS kill_command -- 生成KILL命令 FROM performance_schema.data_lock_waits dw JOIN data_locks r ON dw.REQUESTING_ENGINE_LOCK_ID = r.ENGINE_LOCK_ID JOIN data_locks b ON dw.BLOCKING_ENGINE_LOCK_ID = b.ENGINE_LOCK_ID JOIN threads bt ON b.THREAD_ID = bt.THREAD_ID; ``` #### **优化效果**: - **直接定位阻塞方**: 输出阻塞事务ID(`blocking_trx_id`)和对应的`KILL`命令,快速解除阻塞[^2]。 - **锁等待可视化**: 明确展示“谁在等待谁的锁”,简化死锁分析。 --- ### 4. **元数据锁(MDL)补充查询** 若涉及表结构变更或全局锁,需检查`metadata_locks`: ```sql SELECT * FROM performance_schema.metadata_locks WHERE LOCK_TYPE = 'SHARED_READ' -- 常见阻塞类型 AND OWNER_THREAD_ID IN ( SELECT THREAD_ID FROM data_locks WHERE LOCK_STATUS = 'WAITING' ); ``` > **注**:元数据锁冲突常见于`ALTER TABLE`或全局读锁(`FLUSH TABLES WITH READ LOCK`)[^3]。 --- ### 关键优化建议 1. **索引优化**: 确保`WHERE`条件列和`LOCK_DATA`涉及字段有索引,减少锁范围。 2. **事务拆分**: 避免长事务,将大事务拆分为小操作,降低锁持有时间。 3. **监控策略**: 定期执行锁查询(如每分钟),记录到监控表,结合`pt-deadlock-logger`工具分析。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值