C/多线程/段错误/(可能是)线程队列问题

标签 c multithreading segmentation-fault coredump ucontext

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

   #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(&(保存.context)); 添加到队列(保存);

最佳答案

首先,您的队列实现此时不是线程安全的。您的问题强烈表明该代码将在多线程环境中使用。使用非线程安全队列会给您带来错误的结果,并且可能会发生奇怪的事情(例如 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;
}

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

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

关于C/多线程/段错误/(可能是)线程队列问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25614976/

相关文章:

java - 我希望 main 方法打印出值 x,该值是由正在运行的线程返回的

c - 打印括号对,得到段错误

c++ - R 中的算术在数字上比在整数上更快。这是怎么回事?

c - 在 Linux + Intel 驱动程序上启用合成时,OpenGL 应用程序会产生奇怪的效果

java - AtomicInteger 是基于JNI 实现的吗?

java - 如何识别线程的启动者

C堆栈奇怪的行为

c++ - 段错误,没有核心转储

java - 优化并找到这个不等式的计算

c - 不使用数组来反转数字的程序