使用pthreads

时间:2015-11-22 09:47:32

标签: c pthreads

我正在尝试为我的操作系统类开发一个项目,我在使用pthreads时遇到了SegFault,但我不确定是什么导致了这个问题。

至于该计划,我正在尝试完成以下计划:

  

南非克鲁格国家公园(Kruger National Park)的某处有一个深峡谷,还有一根横跨峡谷的绳索。   狒狒可以通过在绳子上手动摆动来穿过峡谷,但如果两只狒狒朝相反方向相遇,他们将会战斗并摔死。此外,绳索仅足以容纳三只狒狒。如果绳子上同时有更多的狒狒,它就会破裂。假设我们可以教狒狒使用信号量,我们想设计一个具有以下属性的同步方案。

     
      
  1. 一旦狒狒开始穿过,就可以保证到另一边而不会碰到另一边的狒狒。
  2.   
  3. 绳子上永远不会有三个以上的狒狒。应保留穿越绳索的狒狒的顺序;也就是说,他们进入绳索的顺序应该是他们退出绳索的顺序。
  4.   
  5. 在一个方向上徘徊的狒狒不应该禁止狒狒无限期地走向另一边(没有饥饿)。解决此要求,以便保留FIFO顺序。也就是说,一只试图向左/向右交叉的狒狒比一只试图向相反方向穿过的狒狒更早到达的绳索首先进入绳索。
  6.   

基本上,我正在阅读一个文本文件,然后模拟一个FIFO系统,其中一些猴子试图越过一个绳索桥。 奇怪的是,我能够让程序运行几次,但它经常会导致SegFault。

pthread_create(&eastern[i],NULL,(void *) &east_side,(void *)&id[i]);
pthread_create(&western[i],NULL,(void *) &west_side,(void *)&id[i]);

其中east_side和west_side在下方。

void* east_side(void*arg)            
{
    int baboon = *(int*)arg;
    int on_rope;
    sem_wait(&deadlock_protection);
    sem_wait(&east_mutex);
    east++;
    if (east == 1)
    {
        sem_wait(&rope);
        printf("Baboon %d: waiting\n", baboon);
    }
    sem_post(&east_mutex);
    sem_post(&deadlock_protection);
    sem_wait(&counter);
    sem_getvalue(&counter, &on_rope);
    printf("Baboon %d: Cross rope request granted (Current crossing: left to right, Number of baboons on rope: %d)\n", baboon,3-on_rope);
    sleep(travel_time);
    sem_getvalue(&counter, &on_rope);
    printf("Baboon %d: Exit rope (Current crossing: left to right, Number of baboons on rope: %d)\n", baboon, 2-on_rope);
    sem_post(&counter);
    sem_wait(&east_mutex);
    east--;
    if (east == 0)
        sem_post(&rope);
    sem_post(&east_mutex);
}

//thread handling west to east travel
void* west_side(void*arg)    
{
    int baboon = *(int*)arg;
    int on_rope;
    sem_wait(&deadlock_protection);
    sem_wait(&west_mutex);
    west++;
    if (west == 1)
    {
        sem_wait(&rope);
        printf("Baboon %d: waiting\n", baboon);
    }
    sem_post(&west_mutex);
    sem_post(&deadlock_protection);
    sem_wait(&counter);
    sem_getvalue(&counter, &on_rope);
    printf("Baboon %d: Cross rope request granted (Current crossing: right to left, Number of baboons on rope: %d)\n", baboon, 3-on_rope);
    sleep(travel_time);
    sem_getvalue(&counter, &on_rope);
    printf("Baboon %d: Exit rope (Current crossing: right to left, Number of baboons on rope: %d)\n", baboon, 2-on_rope);
    sem_post(&counter);
    sem_wait(&west_mutex);
    west--;
    if (west == 0)
        sem_post(&rope);
    sem_post(&west_mutex);

}

我在

的纯文本文件中使用示例输入
L,R,R,R,R,R,L,L,R

这会创建输出:

sh-4.3 $ main input.txt 5
输入是
L R R R R R L L
狒狒1:请求交叉绳索(从左到右)
狒狒1:等待
狒狒1:允许交叉绳索请求(当前交叉:从左到右,绳索上的狒狒数量:1)
狒狒2:请求交叉绳索(从右到左)
狒狒3:请求交叉绳索(从右到左)
狒狒4:请求交叉绳索(从右到左)
狒狒5:请求交叉绳索(从右到左)
狒狒1:出口绳索(当前交叉口:从左到右,绳索上的狒狒数量:0)
狒狒2:等待
狒狒2:允许交叉绳索请求(当前交叉:从右到左,绳索上的狒狒数量:1)
狒狒3:允许交叉绳索请求(当前交叉:从右到左,绳索上的狒狒数量:2)
狒狒4:允许交叉绳索请求(当前交叉:从右到左,绳索上的狒狒数量:3)
狒狒6:请求交叉绳索(从右到左)
狒狒7:请求交叉绳索(从左到右)
狒狒8:请求交叉绳索(从左到右)
狒狒9:请求交叉绳索(从右到左)
分段错误(核心转储)

我已经包含了整个文件,以防问题实际上不在我认为问题出现的地方。

/*include header files*/

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <semaphore.h>
//#include <stdbool.h>


//compile with command 
//gcc -o main *.c -lpthread -lrt

/*semaphores*/
sem_t rope;
sem_t east_mutex;
sem_t west_mutex;
sem_t deadlock_protection;
sem_t counter;

/*global variables*/
int east = 0;
int west = 0;
int travel_time;    

/*function prototypes*/
void crossing(int x);
void* east_side(void*);
void* west_side(void*);

/*main function*/
int main(int argc, char *argv[])
{ 

    char c;
    int baboonCnt=0;
    char temp[100];

    sem_init(&rope,0,1);                        //ensure mutual exclusion on rope ownership
    sem_init(&east_mutex,0,1);                  //east side on travel
    sem_init(&west_mutex,0,1);                  //west side on travel
    sem_init(&deadlock_protection,0,1);         //used to prevent deadlocks while using semaphores
    sem_init(&counter,0,3);                     //ensure only 3 baboons are allowed on the rope

    //ensure all input arguements are entered
    if ( argc == 3 )                    
    {
        travel_time = atoi(argv[2]);
        FILE *file;
        int baboonCnt=0;
        if (file = fopen(argv[1], "r") )
        {
            while((c=getc(file))!=EOF)
            {
                if(c == 'L'|| c == 'R')
                {
                    temp[baboonCnt] = c;
                    baboonCnt++;
                }
            }
        }
        else   
        {
            printf("Unable to read data from the input file.");
            return 0;
        }
        printf("The input is\n");
        int j=0;
        for(j;j<baboonCnt;++j)
        {
            printf("%c ",temp[j]);
        }
        printf("\n");
        int id[baboonCnt];
        pthread_t eastern[baboonCnt],western[baboonCnt];
        int i=0;
        for(i;i<baboonCnt;++i)
        {
            sleep(1);
            if(temp[i]=='L')
            {
                id[i] = i+1;
                printf("Baboon %d: Request to cross rope (left to right)\n", i+1);
                pthread_create(&eastern[i],NULL,(void *) &east_side,(void *)&id[i]);
            }
            else if(temp[i]=='R')
            {
                id[i] = i+1;
                printf("Baboon %d: Request to cross rope (right to left)\n", i+1);
                pthread_create(&western[i],NULL,(void *) &west_side,(void *)&id[i]);
            }
        }
        int k=0;
        printf("before k loop");
        for(k;k<baboonCnt;++k)
        {

            pthread_join(eastern[k],NULL);
            printf("eastern",k);
            pthread_join(western[k],NULL); 
            printf("western %d",k);         
        }

        //destroy all semaphores
        sem_destroy (&rope); 
        sem_destroy (&east_mutex);
        sem_destroy (&west_mutex);
        sem_destroy (&deadlock_protection);
        sem_destroy (&counter);
        return 0;
    }
    else
    {
        printf("Proper command line usage is: \n<name> <filename> <cross time>\n");
    }
}
//thread handling the east to west to travel
void* east_side(void*arg)            
{
    int baboon = *(int*)arg;
    int on_rope;
    sem_wait(&deadlock_protection);
    sem_wait(&east_mutex);
    east++;
    if (east == 1)
    {
        sem_wait(&rope);
        printf("Baboon %d: waiting\n", baboon);
    }
    sem_post(&east_mutex);
    sem_post(&deadlock_protection);
    sem_wait(&counter);
    sem_getvalue(&counter, &on_rope);
    printf("Baboon %d: Cross rope request granted (Current crossing: left to right, Number of baboons on rope: %d)\n", baboon,3-on_rope);
    sleep(travel_time);
    sem_getvalue(&counter, &on_rope);
    printf("Baboon %d: Exit rope (Current crossing: left to right, Number of baboons on rope: %d)\n", baboon, 2-on_rope);
    sem_post(&counter);
    sem_wait(&east_mutex);
    east--;
    if (east == 0)
        sem_post(&rope);
    sem_post(&east_mutex);
}

//thread handling west to east travel
void* west_side(void*arg)    
{
    int baboon = *(int*)arg;
    int on_rope;
    sem_wait(&deadlock_protection);
    sem_wait(&west_mutex);
    west++;
    if (west == 1)
    {
        sem_wait(&rope);
        printf("Baboon %d: waiting\n", baboon);
    }
    sem_post(&west_mutex);
    sem_post(&deadlock_protection);
    sem_wait(&counter);
    sem_getvalue(&counter, &on_rope);
    printf("Baboon %d: Cross rope request granted (Current crossing: right to left, Number of baboons on rope: %d)\n", baboon, 3-on_rope);
    sleep(travel_time);
    sem_getvalue(&counter, &on_rope);
    printf("Baboon %d: Exit rope (Current crossing: right to left, Number of baboons on rope: %d)\n", baboon, 2-on_rope);
    sem_post(&counter);
    sem_wait(&west_mutex);
    west--;
    if (west == 0)
        sem_post(&rope);
    sem_post(&west_mutex);
}

2 个答案:

答案 0 :(得分:0)

运行valgrind几乎可以检测到你的错误:

==10217== Use of uninitialised value of size 8
==10217==    at 0x4E39241: pthread_join (in /usr/lib64/libpthread-2.18.so)
==10217==    by 0x400E64: main (example.c:103)

第103行是pthread_join(eastern[k],NULL);; valgrind强调东方阵列在没有设置的情况下被读取。

您的阵列未得到满足,您可以访问未设置的元素。 你可以用这种方式修改join循环:

for(k;k<baboonCnt;++k)
{
    if(temp[k]=='L') {
            pthread_join(eastern[k],NULL);
            printf("eastern %d\n",k);
    }
    else if(temp[k]=='R') {
            pthread_join(western[k],NULL);
            printf("western %d\n",k);
    }
}

答案 1 :(得分:0)

正如此线程中的其他人所提到的,我在我的代码中遇到了一个错误,我试图访问那些尚未正确初始化的数组元素。我在这里总结了我对这篇文章的更改。感谢@kaylum帮助我得出这个结论。

这些数组访问发生在这里:

for(k;k<baboonCnt;++k)
    {

        pthread_join(eastern[k],NULL);
        printf("eastern",k);
        pthread_join(western[k],NULL); 
        printf("western %d",k);         
    }

在行中发生不正确的初始化

for(i;i<baboonCnt;++i)
    {
        sleep(1);
        if(temp[i]=='L')
        {
            id[i] = i+1;
            printf("Baboon %d: Request to cross rope (left to right)\n", i+1);
            pthread_create(&eastern[i],NULL,(void *) &east_side,(void *)&id[i]);
        }
        else if(temp[i]=='R')
        {
            id[i] = i+1;
            printf("Baboon %d: Request to cross rope (right to left)\n", i+1);
            pthread_create(&western[i],NULL,(void *) &west_side,(void *)&id[i]);
        }
    }

这两组代码是造成执行问题的原因,包括我遇到的SegFault。 修改初始化部分来创建2个独立的id数组,一个引用东狒狒,另一个引用西狒狒,而不是简单地将所有ID保存在一个组中,这对于使程序工作至关重要。在调整id密钥存储方法之后,还需要修改pthread_join循环,以便它们正确访问数组。

以下是修改后的初始化部分:

int eastcnt=0, westcnt=0, eastid[eastBab], westid[westBab], i=0;
    for(i;i<baboonCnt;++i)
      {
        sleep(1);
        if(temp[i]=='L')
          {
        eastid[eastcnt]=i;
        printf("Baboon %d wants to cross left to right\n",i);
        pthread_create(&eastern[eastcnt],NULL, (void *) &east_side,(void *) &eastid[eastcnt] );
        ++eastcnt;
          }
        else if(temp[i]=='R')
          {
        westid[westcnt]=i;
        printf("Baboon %d wants to cross right to left\n",i);
        pthread_create(&western[westcnt],NULL, (void *) &west_side,(void *) &westid[westcnt] );
        ++westcnt;
          }
      }

和修改后的pthread_join循环

int k =0;
    for(k;k<westBab;++k)
    {
        pthread_join(western[k],NULL); 
    }
    k=0;
    for(k;k<eastBab;++k)
    {
        pthread_join(eastern[k],NULL); 
    }

完成上述更改后,进行一般清理后,整个程序都符合规范。