C/多线程/分段故障/(可能)线程队列出现问题



我正在尝试创建线程库。为此,我试图实现队列来存储要执行的挂起线程。

   #include <ucontext.h>
   #include <stdio.h>
   #include <stdlib.h>
   typedef struct {
       ucontext_t context;
   }MyThread;
   #define MAX 20
   MyThread queue[MAX];
   int rear=0,front=0;
   void addToQueue(MyThread t)
   {
       if(rear==MAX)
       {
           printf("Queue is full!");
           return;
       }        
       queue[front]=t;
       front+=1;
   }
   MyThread* removeFromQueue()
   {       
       if(front==rear)
       return NULL;        
       rear=rear+1;
       return &(queue[rear-1]);       
   }
   MyThread umain;
   void MyThreadInit (void(*start_funct)(void *), void *args)
   {
    getcontext(&(umain.context));
    char p[64000];
       umain.context.uc_stack.ss_sp =(char *)p;
       umain.context.uc_stack.ss_size = sizeof(p);
       umain.context.uc_link =NULL;
       makecontext(&umain.context,(void(*)(void))start_funct,1,args);
       setcontext(&(umain.context));
   }
    MyThread MyThreadCreate (void(*start_funct)(void *), void *arg)
   {
         MyThread newthread;
       char args[10000];
        getcontext(&(newthread.context));
        newthread.context.uc_stack.ss_sp =(char *)args;
        newthread.context.uc_stack.ss_size = sizeof(args);
        newthread.context.uc_link =NULL;
        makecontext(&newthread.context,(void(*)(void))start_funct,1,arg);
        addToQueue(newthread);
        return newthread;
    }         
    void MyThreadYield(void)
    {
        MyThread* a=removeFromQueue();
        MyThread save;
        if(a != NULL)
        {
         printf("Before yielding the context n");
         getcontext(&(save.context));
         addToQueue(save);
         //swapcontext(&umain.context,&(a->context));
         setcontext(a);    
         printf("After the swapping the context n");
        }
        else
        { printf("NULL!!! n");
        }
    }
    void func1(void *arg)
    {
     printf("func1started n");        
     MyThreadYield();
    }
    void func2(void *arg)
    {
     printf("func2started n");
     MyThreadYield();         
    }
    void func12(void *arg)
    {
     printf("func12started n");
     MyThreadCreate(func1,arg);
     MyThreadCreate(func2,arg);
     MyThreadYield();
    }
    int main(void)
    {
        int i=0;
        printf("inside the main function n");
        MyThreadInit(func12,&i);
        return 0;
    }
     Output :
     inside the main function
     func12started
     Before yielding the context
     func1started
     Before yielding the context
     func2started
     Before yielding the context
     func1started
     Before yielding the context
     Segmentation fault

我之所以提到队列,是因为我尝试从"MyThreadYield"函数中删除下面的代码,它运行良好,但不能实现预期的功能
getcontext(&(save.context));addToQueue(保存);

首先,您的队列实现目前不是线程安全的。您的问题强烈建议将在多线程环境中使用此代码。拥有一个非线程安全的队列会给你错误的结果,并且可能会发生奇怪的事情(比如removeFromQueue()向两个不同的线程返回相同的东西,或者addToQueue()在同一位置插入两个项目)。

除此之外,您的队列实现永远不会工作。您没有正确使用frontrear。仔细查看插入函数:

void addToQueue(MyThread t)
{
    if (rear==MAX)
    {
        printf("Queue is full!");
        return;
    }        
    queue[front]=t;
    front+=1;
}

您检查rear是否为MAX,但是,您写入queue[front]并递增front。如果我只是不断地向队列中添加项目,最终达到缓冲区的限制,该怎么办?rear将始终为0,front将无限增长,并且您的函数将写超出queue的限制。这可能是您的分割错误的原因。

我想你想检查一下front

void addToQueue(MyThread t)
{
    if (front == MAX)
    {
        printf("Queue is full!");
        return;
    }        
    queue[front]=t;
    front+=1;
}

只要queue是一个全局数组(因为您返回的是指针,而不能返回指向局部变量的指针),removeFromQueue()的代码看起来表面上是可以的。然而,您必须从这个答案中得出的一个最重要的事实是,您的队列实现在长期内不会扩展。基于数组的队列是一个糟糕的选择。当阵列中的空间用完时,该怎么办?如果我插入MAX元素,然后删除2或3,然后尝试插入更多元素,会怎么样?您的代码会说队列已满,因为它只允许您总共插入MAX个元素。当一个元素被移除时,您可以将队列中的每个元素向左移动,但这太疯狂了,而且效率极低。或者,您可以将frontMAX为模递增,使rear领先于front,只要您知道最多可以插入MAX个元素即可。这会更好,但它会破坏removeFromQueue()中的逻辑,因为在处理队列总灾难时,前面返回的指针可能会指向不同的线程结构。绝对不是你想要的。

一个更好的方法是使用链表来实现这一点,在链表中,您可以保持一个指向头部的指针和一个指向尾部的指针。看看http://en.wikipedia.org/wiki/Queue_(abstract_data_type)#Queue_implementation

相关内容

  • 没有找到相关文章

最新更新