我正在尝试在 c 中实现简单的用户级线程库。当一个线程启动并且该线程调用第二个线程时。这第二个线程运行正常,但当它退出时程序崩溃。这是我的编码。
//**********************************************
#include <setjmp.h>
typedef void *any_ptr;
/* Define Boolean type, and associated constants. */
typedef int Boolean;
typedef void (*ThreadFunc)(any_ptr);
#define TRUE ((Boolean)1);
#define FALSE ((Boolean)0);
typedef struct TheadSystem
{
queue<any_ptr> readyQ;
// currently executing thread
jmp_buf lastContext; // location on which the system jumps after all threads have exited
char name[30]; // optional name string of a thread, may be used for debugging
jmp_buf context; // saved context of this thread
signal_t *sig; // signal that wakes up a waiting thread
ThreadFunc func; // function that this thread started executing
any_ptr arg;
}TheadSystem;
void t_start(ThreadFunc f, any_ptr v, char *name);
void t_yield();
void block();
void unblock();
void t_sig(Condition cond, any_ptr val, Boolean queue_signal);
void t_fork(ThreadFunc f, any_ptr v, char *name);
void t_exit(int val);
我对threads.h的实现
#include "threads.h"
#include<iostream>
#include<queue>
using namespace std;
TheadSystem th;
queue<any_ptr> blocked_queue;
jmp_buf set_env,ready_env,yeild_buf;
void t_start(ThreadFunc f, any_ptr v, char *name){
if(!th.ready_queue.empty()){
cout<<"sorry thread already started now you have to create by t_fork:"<<endl;
}
else{
th.ready_queue.push(th.context);
if(!setjmp(th.context)){
memcpy(th.lastContext,th.context,sizeof(jmp_buf));
th.arg=v;
th.func=f;
//memcpy(th.currentThread->context,set_env,sizeof(jmp_buf));
//cout<<"when jmp buf set then:"<<endl;
th.ready_queue.push(th.context);
th.func(th.arg);
}
//cout<<"after come back from long jump:"<<endl;
}
}
void t_yield(){
jmp_buf *j=(jmp_buf *)th.ready_queue.front();
th.ready_queue.front()=th.context;
longjmp(*j,2);
}
void t_fork(ThreadFunc f, any_ptr v, char *name){
memcpy(th.lastContext,th.context,sizeof(jmp_buf));
if(!setjmp(th.context)){
f(v);
th.ready_queue.push(th.context);
}else
{
}
}//end of t_fork
void t_exit(int val){
cout<<"before long jump in t_exit"<<endl;
jmp_buf *j=(jmp_buf *)th.ready_queue.front();
th.ready_queue.pop();
longjmp(*j,2);
}
void block(){
blocked_queue.push(th.context);
jmp_buf *j=(jmp_buf *)th.ready_queue.front();
th.ready_queue.pop();
longjmp(*j,2);
}
void unblock(){
th.ready_queue.push(th.context);
jmp_buf *j=(jmp_buf *)blocked_queue.front();
blocked_queue.pop();
longjmp(*j,2);
}
我的测试用例是
#include<iostream>
#include<setjmp.h>
#include<stdio.h>
#include "threads.h"
#include<queue>
using namespace std;
void fun2(any_ptr v){
cout<<"in 2nd function:"<<endl;
t_exit(0);
}
void helloworld(any_ptr v){
cout<<"in hello world from start"<<endl;
t_fork(fun2,NULL,"no value");
cout<<"after second thread:"<<endl;
cout<<"before exit"<<endl;
t_exit(0);
}
void main(){
cout<<"1 start"<<endl;
t_start(helloworld, NULL, "my function");
cout<<"main function"<<endl;
}//end of void main
最佳答案
这是一个问题:
在 t_start
函数中,您可以这样做:
th.ready_queue.push(th.context);
ready_queue
是一个指针队列,但是th.context
不是指针。
然后在 t_yield
函数中做
jmp_buf *j=(jmp_buf *)th.ready_queue.front();
所以你压入非指针对象,并将它们作为指针弹出。如果您尝试将非指针对象作为指针访问,则您有 undefined behavior .
你的代码,如果编译没有错误,至少应该给你很多警告,如果你只得到几个警告,那么我建议你启用更多的警告。当编译器向您发出警告时,通常表示您正在做一些您不应该做的事情,比如做一些只会导致未定义行为的事情。只是通过例如使警告静音类型转换是一个非常糟糕的解决方案,因为它实际上并没有解决警告的原因。
此外,使用 void*
是坏代码出现的一个很好的标志。如果可以避免,请不要使用它,在这种情况下,在您使用它的大多数地方(例如 ready_queue
)实际上不需要它。
关于c++ - 在 C++ 中使用 set_jmp/longjmp 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23357161/