我试图编写一个库来管理线程使用上下文(getcontext,setcontext,makecontext,swapcontext),没有pthreads。
函数MyThreadYield(),暂停当前线程上下文,将其发送到就绪队列的末尾,并开始在就绪队列的头部执行线程。
在MyThreadYield()中,我能够通过swapcontext()检索暂停线程的上下文,但是当它返回到函数执行时,我得到一个段错误。
例如: - 假设线程1是init线程,它运行并创建线程2.然后它产生。现在线程2运行,然后调用yield。这里swapcontext运行,我可以通过"%p"验证交换是否成功。但是当它试图从MyThreadYield()返回以恢复线程1的函数运行时,我得到了seg错误。
这是我的图书馆代码: -
typedef void *MyThread;
typedef void *MySemaphore;
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <ucontext.h>
#include <string.h>
// structure of threads
struct tnode {
ucontext_t* ctextptr;
int tid; // own thread id
int pid; // parent thread id
} ;
struct tnode* cthread = NULL;
// linked list for ready queue
struct rnode {
struct tnode* thread;
struct rnode* next;
} ;
struct rnode* rhead = NULL;
struct rnode* rtail;
static int tindex; // will generate thread id (tid) for new threads
// linked list for blocked queue
struct bnode {
struct tnode* thread;
struct bnode* next;
int wid[20]; // tid of threads bthread is waiting on //limit is 20
} ;
struct bnode* bhead = NULL;
struct bnode* btail;
int b; // keeps track of size of bacche
int bacche[20]; // array to store children of current running thread
//Pushes blocked thread into the blocked linked list
void AddToBlist (struct tnode* thd , char s[])
{
struct bnode* newbie = NULL;
newbie = malloc (sizeof(struct bnode));
newbie->thread = thd;
int i;
for(i=0; i<20; i++)
newbie->wid[i] = 0;
char * pch; i=0;
pch = strtok(s," "); //Reference : http://stackoverflow.com/questions/4513316/split-string-in-c-every-white-space
while (pch!=NULL)
{
newbie->wid[i] = atoi(pch);
i++;
pch = strtok (NULL, " ");
}
printf("\n thread wait array : \t"); //ff
for(i=0; i<20; i++)
printf("%d\t",newbie->wid[i]); //ff
newbie->next = NULL;
btail = newbie;
if(bhead==NULL)
{
bhead = newbie;
} else {
struct bnode* current = bhead;
while (current->next != NULL)
{
current = current->next;
}
current->next = newbie;
}
}
// Scan blocked queue to find a matching thread as specified by id
int scanB (int id)
{
int retval = 0;
struct bnode* current = bhead;
while (current != NULL)
{
if((current->thread)->tid == id )
{
retval = 1;
break;
}
current = current->next;
}
return retval;
}
// Scan blocked queue for parent id listed
int scanBP (int id)
{
int retval = 0;
struct bnode* current = bhead;
while (current != NULL)
{
if((current->thread)->pid == id )
{
bacche[b] = (current->thread)->tid;
b++;
retval ++;
}
current = current->next;
}
return retval;
}
// Clears a blocked thread and moves it to ready queue
// Reference : https://www.cs.bu.edu/teaching/c/linked-list/delete/
void clearB (int id)
{
if (bhead==NULL)
{
//return NULL;
}
struct bnode* bcur = bhead;
struct bnode* bpre = bhead;
while (bcur!= NULL)
{
int i;
for(i=0; i<20; i++)
{
if (bcur->wid[i] == id)
{
bcur->wid[i] = 0;
break;
}
}
int k = 0;
for(i=0; i<20; i++)
{
if (bcur->wid[i] == 0)
k++;
}
if (k==20)
{
printf("\n thread no longer blocked .... moving to ready queue \n"); //ff
AddToRlist(bcur->thread);
if (bcur == bhead)
{
struct bnode* temp = bhead;
bhead = bhead->next;
free(temp);
bcur = bhead;
bpre = bhead;
} else {
struct bnode* temp = bcur;
bcur = bcur->next;
bpre->next = bcur;
free(temp);
}
} else {
bpre = bcur;
bcur = bcur->next;
}
}
}
//Pushes newly created context into the linked list
void AddToRlist (struct tnode* thd)
{
struct rnode* newbie = NULL;
newbie = malloc (sizeof(struct rnode));
newbie->thread = thd;
newbie->next = NULL;
rtail = newbie;
if(rhead==NULL)
{
rhead = newbie;
} else {
struct rnode* current = rhead;
while (current->next != NULL)
{
current = current->next;
}
current->next = newbie;
}
}
// Scan ready queue to find a matching thread as specified by id
int scanR (int id)
{
int retval = 0;
struct rnode* current = rhead;
while (current != NULL)
{
if((current->thread)->tid == id )
{
retval = 1;
break;
}
current = current->next;
}
return retval;
}
// Checks for parent id among ready queue elements
int scanRP (int id)
{
int retval = 0;
struct rnode* current = rhead;
while (current != NULL)
{
if((current->thread)->pid == id )
{
bacche[b] = (current->thread)->tid;
b++;
retval++;
}
current = current->next;
}
return retval;
}
// ****** THREAD OPERATIONS ******
// Create a new thread.
MyThread MyThreadCreate(void(*start_funct)(void *), void *args)
{
tindex++;
struct tnode* tnew = NULL;
tnew = malloc(sizeof (struct tnode));
memset(tnew, 0, sizeof(struct tnode));
tnew->tid = tindex;
tnew->pid = cthread->tid;
char stc[8192];
tnew->ctextptr = (ucontext_t *) malloc(sizeof(ucontext_t));
getcontext(tnew->ctextptr);
tnew->ctextptr->uc_stack.ss_sp = stc;
tnew->ctextptr->uc_stack.ss_size = sizeof stc;
tnew->ctextptr->uc_stack.ss_flags = 0;
tnew->ctextptr->uc_link = NULL;
makecontext(tnew->ctextptr, (void (*)(void))start_funct, 1, args);
AddToRlist(tnew);
return((MyThread)tnew);
}
// Yield invoking thread
void MyThreadYield(void)
{
if (rhead == NULL)
{
return;
} else {
printf("cthread addr :%p\n",cthread);
printf("rhead thd addr :%p\n",rhead->thread);
AddToRlist(cthread);
cthread = rhead->thread;
rhead = rhead->next;
printf("rtail thd addr :%p\n",rtail->thread);
printf("cthread addr :%p\n",cthread);
printf("\n before swap\n"); //ff
int ty = swapcontext((rtail->thread)->ctextptr, cthread->ctextptr);
printf("\n after swap ty = %d, cthread tid :%d\n",ty,cthread->tid); //ff
}
}
// Join with a child thread
int MyThreadJoin(MyThread thread)
{
if (cthread->tid != ((struct tnode*)thread)->pid)
{
printf("\n Join Thread not a child of invoking thread, returning -1 \n");
return -1;
}
int check_rlist = scanR(((struct tnode*)thread)->tid);
int check_blist = scanB(((struct tnode*)thread)->tid);
if (check_rlist == 0 && check_blist == 0)
{
printf("\n Join Thread seems to have been terminated, returning -1 \n");
return -1;
}
printf ("\n Join call successful, proceeding with join operation \n");
int wid = ((struct tnode*)thread)->tid;
char w[15];
sprintf(w, "%d", wid);
AddToBlist(cthread,w);
cthread = rhead->thread;
rhead = rhead->next;
printf("\n before swap inside join\n"); //ff
int tj = swapcontext((btail->thread)->ctextptr, cthread->ctextptr);
printf("\n after swap tj = %d, cthread tid :%d\n",tj,cthread->tid); //ff
}
// Join with all children
void MyThreadJoinAll(void)
{
int k; b=0;
for(k=0;k<20;k++)
bacche[k]=0;
int check_rlist = scanRP(cthread->tid);
int check_blist = scanBP(cthread->tid);
if (check_blist == 0 && check_rlist == 0)
{
printf("\n can't find any active children, exiting joinall \n");
return;
}
printf("\n generated bacche array : \t"); //ff
for(k=0;k<20;k++) //ff
printf("%d\t",bacche[k]); //ff
int len;
char s[50]="\0";
for (k=0;k<b;k++)
{
char dig = (char)(((int)'0')+bacche[k]);
len=strlen(s);
s[len]=dig; s[len+1]=' '; s[len+2]='\0';
}
printf("\n generated wid string : [%s] \n",s); //ff
printf("cthread addr :%p\n",cthread);
printf("rhead addr :%p\n",rhead->thread);
AddToBlist(cthread,s);
cthread = rhead->thread;
rhead = rhead->next;
printf("\n before swap inside join all\n"); //ff
printf("btail tid :%d\n",(btail->thread)->tid);
printf("cthread tid :%d\n",cthread->tid);
printf("btail thd addr :%p\n",btail->thread);
printf("cthread addr :%p\n",cthread);
int tj = swapcontext((btail->thread)->ctextptr, cthread->ctextptr);
printf("\n after swap tj = %d, cthread tid :%d\n",tj,cthread->tid); //ff
}
// Terminate invoking thread
void MyThreadExit(void)
{
printf("\n In thread exit \n"); //ff
clearB(cthread->tid); //Move threads blocked on current thread to ready queue
printf("\n clearB done \n"); //ff
printf("\n removing parent (invoking) thread's children \n"); //ff
if (rhead == NULL)
{
printf("\n ready queue is empty, exiting \n"); //ff
//cthread = NULL;
//setcontext (NULL);
} else {
cthread = rhead->thread;
rhead = rhead->next;
printf("cthread tid :%d\n",cthread->tid);
setcontext (cthread->ctextptr);
}
}
// ****** SEMAPHORE OPERATIONS ******
// Create a semaphore
MySemaphore MySemaphoreInit(int initialValue);
// Signal a semaphore
void MySemaphoreSignal(MySemaphore sem);
// Wait on a semaphore
void MySemaphoreWait(MySemaphore sem);
// Destroy on a semaphore
int MySemaphoreDestroy(MySemaphore sem);
// ****** CALLS ONLY FOR UNIX PROCESS ******
// Create and run the "main" thread
void MyThreadInit(void(*start_funct)(void *), void *args)
{
tindex = 1;
cthread = malloc (sizeof(struct tnode));
memset(cthread, 0, sizeof(struct tnode));
cthread->tid = tindex;
cthread->pid = 0;
ucontext_t* ctxmain;
ctxmain = (ucontext_t *) malloc(sizeof(ucontext_t));
getcontext(ctxmain);
char sti[8192];
cthread->ctextptr = (ucontext_t *) malloc(sizeof(ucontext_t));
getcontext(cthread->ctextptr);
cthread->ctextptr->uc_stack.ss_sp = sti;
cthread->ctextptr->uc_stack.ss_size = sizeof sti;
cthread->ctextptr->uc_link = ctxmain;
cthread->ctextptr->uc_stack.ss_flags = 0;
makecontext(cthread->ctextptr, (void (*)(void))start_funct, 1, args);
swapcontext(ctxmain, cthread->ctextptr);
}
以下是使用此库的程序: -
#include <stdio.h>
#include "mythread.h"
int n;
void t1(void * who)
{
int i;
printf("\n checkpoint 2 \n");
printf("\n who: %d \n",(int)who);
//sleep(5);
printf("t%d start\n", (int)who);
for (i = 0; i < n; i++) {
printf("t%d yield\n", (int)who);
printf("\n oogaa \n");
MyThreadYield();
printf("\n boogaa \n");
}
printf("t%d end\n", (int)who);
MyThreadExit();
printf("\n checkpoint 3 \n");
}
void t0(void * dummy)
{
printf("\n dummy: %d \n",(int)dummy);
//sleep(5);
printf("\n checkpoint 1 \n");
MyThreadCreate(t1, (void *)1);
printf(" hello 6\n");
t1(0);
printf("\n checkpoint 4 \n");
}
int main(int argc, char *argv[])
{
if (argc != 2)
return -1;
n = atoi(argv[1]);
MyThreadInit(t0, (void*)7);
printf("\n checkpoint 5 \n");
}
以下是传递参数n = 2的程序的输出: -
eos$ ./ping.exe 2
dummy: 7
checkpoint 1
hello 6
checkpoint 2
who: 0
t0 start
t0 yield
oogaa
cthread addr :0x1151010
rhead thd addr :0x1151790
rtail thd addr :0x1151010
cthread addr :0x1151790
before swap
checkpoint 2
who: 1
t1 start
t1 yield
oogaa
cthread addr :0x1151790
rhead thd addr :0x1151010
rtail thd addr :0x1151790
cthread addr :0x1151010
before swap
after swap ty = 0, cthread tid :1
boogaa
t0 yield
oogaa
cthread addr :0x1151010
rhead thd addr :0x1151790
rtail thd addr :0x1151010
cthread addr :0x1151790
before swap
after swap ty = 0, cthread tid :2
Segmentation fault (core dumped)
如上所示,我的调试消息表明地址已正确交换,因此我无法找出segfault的原因。
尝试使用gdb对它进行调试,但是我在我的智慧结束时仍然没有任何线索。
任何帮助都将受到高度赞赏!
答案 0 :(得分:3)
我能够通过朋友的帮助解决这个问题。 我非常愚蠢和琐碎的错误。 我试图通过本地堆栈将内存分配给上下文,这可能会被杀死并导致问题。请参阅下面的注释行: -
//char sti[8192];
//cthread->ctextptr->uc_stack.ss_sp = sti;
//cthread->ctextptr->uc_stack.ss_size = sizeof sti;
在将以上行更改为以下内容并使用直接分配时,我的代码运行正常。
cthread->ctextptr->uc_stack.ss_sp = malloc(8192);
cthread->ctextptr->uc_stack.ss_size = 8192;