linux中的信号量操作,接收SIGSEGV和分段错误,哪部分错了?

时间:2015-07-28 06:53:00

标签: c linux pthreads

我的线程功能是:

#include"stdio.h"
#include"sys/types.h"
#include"pthread.h"
#include"semaphore.h"

sem_t sem;
int running = 1;
int ret;
void *pf(void *arg)          //producer function
{
    int semval;
    while(running)
    {
        sleep(1);
        sem_post(&sem); 
        sem_getvalue(&sem,&semval); 
        printf("produce : %d\n",semval);
    }

}

void *cf(void *arg)         /*consumer function*/
{
    int semval;
    while(running)
    {
        sleep(1);
        sem_wait(&sem); 
        sem_getvalue(&sem,&semval);
        printf("consume : %d\n",semval);
    }
}

主要功能是:

int main()
{
    pthread_t pf, cf;
    ret = sem_init(&sem,0,16);
    pthread_create(&pf,NULL,(void *)pf,NULL);   /*create producer*/
    pthread_create(&cf,NULL,(void *)cf,NULL);   /*create consumer*/
    sleep(1);
    running = 0;
    pthread_join(pf,NULL);
    pthread_join(cf,NULL);
    sem_destroy(&sem);  
    return 0;
}

当我运行可执行文件时,它会返回分段错误。我认为该程序可能访问无效内存,但我不知道我的代码的哪一部分是错误的!

2 个答案:

答案 0 :(得分:3)

您已使用相同名称命名了线程变量和函数:pfcf。所以变量shadow是函数名。变量和函数具有相同的名称永远不是一个好主意。

更改

pthread_create(&pf,NULL,(void *)pf,NULL);   /*create producer*/
pthread_create(&cf,NULL,(void *)cf,NULL);   /*create consumer*/

pthread_create(&pf,NULL,producer,NULL);   /*create producer*/
pthread_create(&cf,NULL,consumer,NULL);   /*create consumer*/

并将您的功能重命名为producerconsumer。请注意,我已删除的转换也是错误的(即使你正确投射也是不必要的)。

您正在从线程函数返回任何值。线程函数应该返回void *。所以你需要调用pthread_exit(NULL);或返回一个空指针。

另一个主要问题是您访问变量running而没有任何导致race condition的同步。这是undefined behaviour。根据线程调度,如果线程在执行之前main线程将running设置为0,那么您的线程可能根本不执行while循环。

答案 1 :(得分:2)

<input type="text" id="lat" placeholder="Latitude &#176;" value=""> &#176;

您实际上是将线程描述符传递给pthread_t pf, cf; ret = sem_init(&sem,0,16); pthread_create(&pf,NULL,(void *)pf,NULL); /*create producer*/ pthread_create(&cf,NULL,(void *)cf,NULL); /*create consumer*/ 作为启动例程。它们与您在这里看起来的功能具有相同的名称,但会影响它们。另请注意,pthread_create()是指向数据的指针,它与函数指针不兼容 - &gt;在这里强制转换为void *

正确的代码会例如看起来像这样:

void *

BTW,一般提示:启用编译器警告:pthread_t pt, ct; ret = sem_init(&sem,0,16); pthread_create(&pt,NULL,pf,NULL); /*create producer*/ pthread_create(&ct,NULL,cf,NULL); /*create consumer*/ 会告诉你出了什么问题。

编辑关于 Blue Moon 的回答:回答:只使用gcc -Wall -Wextra来关闭你的主题 有问题。这里发生的数据竞争在大多数情况下在实践中并不重要,因为通常情况下,您只想告诉您的线程停止并且不关心,正是这种情况发生时。但是(那是一个很大的但是):你的编译器会看到这段代码:

int

while(running) { [...] } 的条件是此函数中while唯一访问权限。不了解并发性,它可以合法地假设running一旦读取,就永远不会改变。因此,读取一次并将此读取值(例如存储在寄存器中)永远用于循环条件将是有效的优化,绝对不是您想要的。

哦,将running添加到volatile 解决方案,但对此的解释往往很长,只是google for it。

一种可能性是使用信号量来停止线程。例如。我在我的一个线程项目中有这个:

running

主线程只执行一个/* check whether daemon shutdown was requested */ if (!sem_trywait(&forceExit)) { /* pass on to next thread */ sem_post(&forceExit); rcout = -2; break; } 来关闭所有其他线程。