线程和上下文切换C++
Threads and context switch C++
我需要帮助来理解以下代码段。它是用 C++(BC31 编译器(编写的线程工作和上下文切换的示例。
我理解为什么PCB存在是为了切换上下文(特别是为了保持SS和SP寄存器(,我也明白通过使用这个程序可以 回到它被打断的点,就像什么都没发生一样。关于代码,我了解宏DISABLE_INTERRUPT和ENABLE_INTERRUPT的用途 (忽略代码某些敏感部分的中断(。我还了解函数createProcess,其中创建了每个线程的本地堆栈以及 线程的标志、段和偏移量将写入其中。在函数 timerISR 中,我了解正在完成上下文切换的部分(写入和读取 SS 和 SP(。
对于其余的代码,我不能说我理解它。函数 returnNextThread((, initNewRoutine((, returnOldRoutine((, finishThread(( 的意义何在?
不过,我最感兴趣的是这个程序是如何同时运行的,那里实际发生了什么,以便这三个函数在运行时交错......
这一切是如何工作的? 我真的很感激一个简单的解释。
#include<stdio.h>
#include<stdlib.h>
#include<iostream.h>
#include<dos.h>
typedef struct PCB_struct {
unsigned ss;
unsigned sp;
unsigned finished;
unsigned quant;
} PCB;
#define DISABLE_INTERRUPT asm cli
#define ENABLE_INTERRUPT asm sti
PCB *threads[4];
volatile unsigned addressOfInterruptVector = 0x08;
volatile unsigned adressOfFreePlaceForInterrupt = 0x60;
volatile unsigned numberOfInterrupts=0;
volatile PCB *activeThread;
volatile unsigned activeThreadNumber=0;
volatile unsigned numberOfFinishedThreads=0;
volatile int necessarilyContextSwitch=0;
PCB* returnNextThread() {
if(activeThreadNumber==0) {
if(threads[1]->finished==0) {
activeThreadNumber=1;
return threads[1];
}
else if(threads[2]->finished==0) {
activeThreadNumber=2;
return threads[2];
}
else if(threads[3]->finished==0) {
activeThreadNumber=3;
return threads[3];
}
else {
activeThreadNumber=0;
return threads[0];
}
}
else if(activeThreadNumber==1) {
if(threads[2]->finished==0) {
activeThreadNumber=2;
return threads[2];
}
else if(threads[3]->finished==0) {
activeThreadNumber=3;
return threads[3];
}
else {
activeThreadNumber=0;
return threads[0];
}
}
else if(activeThreadNumber==2) {
if(threads[1]->finished==0) {
activeThreadNumber=1;
return threads[1];
}
else if(threads[3]->finished==0) {
activeThreadNumber=3;
return threads[3];
}
else {
activeThreadNumber=0;
return threads[0];
}
}
else if(activeThreadNumber==3) {
if(threads[2]->finished==0) {
activeThreadNumber=2;
return threads[2];
}
else if(threads[1]->finished==0) {
activeThreadNumber=1;
return threads[1];
}
else {
activeThreadNumber=0;
return threads[0];
}
}
activeThreadNumber=0;
return threads[0];
}
unsigned tmpSs=0;
unsigned tmpSp=0;
void interrupt timerISR() {
if(!necessarilyContextSwitch) numberOfInterrupts--;
if(numberOfFinishedThreads<3 && (numberOfInterrupts==0 || necessarilyContextSwitch==1)) {
asm {
mov tmpSs,ss
mov tmpSp,sp
}
activeThread->ss=tmpSs;
activeThread->sp=tmpSp;
activeThread=returnNextThread();
tmpSs=activeThread->ss;
tmpSp=activeThread->sp;
numberOfInterrupts=activeThread->quant;
asm {
mov ss,tmpSs
mov sp,tmpSp
}
}
if(!necessarilyContextSwitch) asm int 60h;
necessarilyContextSwitch=0;
}
unsigned oldRoutineOffset, oldRoutineSegment;
void initNewRoutine() {
unsigned offsetAddress=addressOfInterruptVector*4;
unsigned segmentAddress=addressOfInterruptVector*4+2;
unsigned emptyOffset=adressOfFreePlaceForInterrupt*4;
unsigned emptySegment=adressOfFreePlaceForInterrupt*4+2;
DISABLE_INTERRUPT
asm {
push es
push ax
push di
mov ax,0
mov es,ax
mov di, word ptr segmentAddress
mov ax, word ptr es:di
mov word ptr oldRoutineSegment, ax
mov word ptr es:di, seg timerISR
mov di, word ptr offsetAddress
mov ax, word ptr es:di
mov word ptr oldRoutineOffset, ax
mov word ptr es:di, offset timerISR
mov di, word ptr emptyOffset
mov ax, word ptr oldRoutineOffset
mov word ptr es:di, ax
mov di, word ptr emptySegment
mov ax, word ptr oldRoutineSegment
mov word ptr es:di, ax
pop di
pop ax
pop es
}
ENABLE_INTERRUPT
}
void returnOldRoutine() {
unsigned offsetAddress=addressOfInterruptVector*4;
unsigned segmentAddress=addressOfInterruptVector*4+2;
DISABLE_INTERRUPT
asm {
push es
push ax
push di
mov ax,0
mov es,ax
mov di, word ptr segmentAddress
mov ax, word ptr oldRoutineSegment
mov word ptr es:di, ax
mov di, word ptr offsetAddress
mov ax, word ptr oldRoutineOffset
mov word ptr es:di, ax
pop di
pop ax
pop es
}
ENABLE_INTERRUPT
}
int finishThread() {
necessarilyContextSwitch=1;
DISABLE_INTERRUPT
activeThread->finished=1;
cout << "Thread " << activeThreadNumber << " finished." << endl;
ENABLE_INTERRUPT
timerISR();
return 0;
}
void function1() {
for(int i=0;i<30;i++) {
cout << "Execution: function 1: " << i << endl;
for(int j=0;j<10000;j++) {
for(int k=0;k<30000;k++);
}
}
finishThread();
}
void function2() {
for(int i=0;i<30;i++) {
cout << "Execution: function 2: " << i << endl;
for(int j=0;j<10000;j++) {
for(int k=0;k<30000;k++);
}
}
finishThread();
}
void function3() {
for(int i=0;i<30;i++) {
cout << "Execution: function 3: " << i << endl;
for(int j=0;j<10000;j++) {
for(int k=0;k<30000;k++);
}
}
finishThread();
}
void createProcess(PCB *block, void (*method)()) {
unsigned* st1 = new unsigned[1024];
st1[1023] = 0x200;
st1[1022] = FP_SEG(method);
st1[1021] = FP_OFF(method);
block->sp = FP_OFF(st1+1012);
block->ss = FP_SEG(st1+1012);
block->finished=0;
}
void mainThread() {
for(int i=0;i<30;i++) {
DISABLE_INTERRUPT
cout << "Main Thread: " << i << endl;
ENABLE_INTERRUPT
for(int j=0;j<30000;j++) {
for(int k=0;k<30000;k++);
}
}
}
int main() {
DISABLE_INTERRUPT
threads[1]=new PCB();
createProcess(threads[1], function1);
threads[1]->quant=20;
threads[2]=new PCB();
createProcess(threads[2], function2);
threads[2]->quant=40;
threads[3]=new PCB();
createProcess(threads[3], function3);
threads[3]->quant=20;
threads[0]=new PCB();
activeThread=threads[0];
activeThreadNumber=0;
activeThread->quant=20;
numberOfInterrupts=activeThread->quant;
ENABLE_INTERRUPT
initNewRoutine();
mainThread();
returnOldRoutine();
cout << "Main program finished." << endl;
return 0;
}
这是可怕的代码(老不是借口(。无论如何,timerISR
每隔一段时间就会触发,并切换到由returnNextThread
确定的适当线程(基本上是调度程序(。
显然,finishThread
通过标记线程已完成并强制上下文切换来结束线程。哪一部分不清楚?
initNewRoutine
和returnOldRoutine
只需安装和卸载计时器 ISR(不幸的命名(。
这看起来像是在非常旧的CPU上实现的自主任务调度程序。您可能需要一个非常旧的系统才能运行它。
在高级别上,代码的功能如下:
- PCB块只是每个线程的属性.它们维护 2 个寄存器的值、切片(线程在 CPU 上花费了多长时间(并标记它是否已完成
- 当您创建新线程(进程(时,此结构将被初始化,但不会发生任何其他操作
- 每当时间阈值过后,CPU 都会自动触发 timerInterrupt。看到中断后,中断处理程序会分析结构,并通过调用 CPU 中断切换到相应的线程。
- 与互斥锁相比,旋转锁可以保证上下文切换
- 线程,如果else语句,都是错误的上下文切换后,会发生什么
- 为什么 Perf 具有如此高的上下文切换?
- 线程和上下文切换C++
- 实现上下文切换 - 第二个函数不再运行
- 为什么共享内存(在IPC中)不需要上下文切换?这是内核空间的内存,可以映射到用户空间
- 在运行时从OpenGL上下文切换到D3D/DX上下文(或其他上下文)
- 当任何子线程导致错误时,上下文切换到主线程
- 在 C++ 中输入关键部分和上下文切换
- 最小化进程之间的上下文切换时间
- 有人知道上下文切换吗?通过FSYNC和syslog ng从应用程序到磁盘的日志记录
- 减少具有相同优先级的线程之间的上下文切换
- 非自愿上下文切换的原因
- Qt,多线程上下文切换与QRadioButtons
- Std::this_thread::sleep_for语言 - 是上下文切换到这个线程
- 上下文切换将如何引起竞态条件
- 如何知道何时发生线程上下文切换
- 如何度量和修复上下文切换瓶颈
- 是否有可能检测到一个线程在Linux中被上下文切换[挂起]
- std::condition_variable::notify_one()在没有上下文切换的情况下调用了多次