使用POSIX线程:程序每隔四或五次运行一次,但看起来似乎有效

时间:2017-10-27 03:47:56

标签: c multithreading pthreads posix

我有一个C程序,我必须编写,创建4个线程。这些4"海盗"线程应该从洞穴中获取1000颗珍珠。 (价值1000的双倍),从洞穴中取出10%或15%。"他们应该一次只能去一个,并且当珍珠洞是空的时候,程序应该停止。该程序似乎运行正常,但在执行几次运行后挂起。

为什么会这样?

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <math.h>

#define NUM_PIRATE_THREADS 4
#define OPEN_SESAME 0
#define OPEN_WATERMELON 1

/* array of threads */
static pthread_t *thread_handles;

/* mutual exlusion lock; mutual exclusion considered in this version */
pthread_mutex_t mutex;

/* pirate thread function */
void *pirate(void* rank);

/* total number of items in resource (pearls in the cave) */
static double cavePearls = 1000.00;

/* amount of pearls pirate thread may take */
static double pearlsToGrab;

/* array to store the number of pearls garnered by each pirate */
int piratesBooty[NUM_PIRATE_THREADS];

/* main function */
int main() {

    /* variable to loop through threads and output pearl consumption */
    long threadIndex;

    /* thread variable */
    long currentThread;

    /* initialize thread_handles array */
    thread_handles = (pthread_t*)malloc(NUM_PIRATE_THREADS*sizeof(pthread_t));

    /* create pirate threads...ARGGG!*/
    for (currentThread = 0; currentThread < NUM_PIRATE_THREADS; ++currentThread) {
        pthread_create(&thread_handles[currentThread], NULL, (void *(*)(void *))pirate, (void*)currentThread);
    }

    /* join pirate threads...ARGGG!*/
    for (currentThread = 0; currentThread < NUM_PIRATE_THREADS; ++currentThread) {
        pthread_join(thread_handles[currentThread], NULL);
    }

    /* update your final cave pearl number to a whole integer value */
    cavePearls = ceil(cavePearls);

    /* display pearl data after thread(s) execution */
    printf("\nPearls left in cave: %d\n", (int)cavePearls);
    for (threadIndex = 0; threadIndex < NUM_PIRATE_THREADS; ++threadIndex){
        printf("Pirate %ld: %d pearls\n", threadIndex, piratesBooty[threadIndex]);
    }

    /* free memory */
    free(thread_handles);

    return 0;
}

void *pirate(void* rank) {

    while(1) { /* continue execution as long as there are still pearls in the cave */
        if (cavePearls == 0) /* cave has been emptied, pirates should stop */
            return 0;

        /* identify which pirate thread you are executing */
        long my_rank = (long)rank;

        /* CRITICAL SECTION LOCKED */
        pthread_mutex_lock(&mutex);

        if (cavePearls) {
            if (my_rank % 2 == OPEN_SESAME) { /* if thread is 0 or 2: "Open, sesame" pirate */
                pearlsToGrab = cavePearls * 0.10; /* "open sesame" = 10% of pearls removed */
                pearlsToGrab = ceil(pearlsToGrab); /* get the ceiling if not an integer value */
                cavePearls = cavePearls - pearlsToGrab; /* update the number of pearls in cave */
                piratesBooty[my_rank] += pearlsToGrab; /* update pirate thread total pearls taken */

            }
            else if (my_rank % 2 == OPEN_WATERMELON){ /* if thread is 1 or 3: "Open, watermelon" pirate */
                pearlsToGrab = cavePearls * 0.15; /* "open watermelon" = 15% of pearls removed */
                pearlsToGrab = ceil(pearlsToGrab); /* get the ceiling if not an integer value */
                cavePearls = cavePearls - pearlsToGrab; /* update the number of pearls in cave */
                piratesBooty[my_rank] += pearlsToGrab; /* update pirate thread total pearls taken */
            }
        } /* end of while-loop */

        /* CRITICAL SECTION UNLOCKED */
        pthread_mutex_unlock(&mutex);

        /* DEBUG SCRIPT
         printf("I am thread %ld, I have %d pearls, I'm taking %d pearls, and \nthere are %d pearls left"
         "in the cave.\n\n", my_rank, piratesBooty[my_rank], (int)pearlsToGrab, (int)cavePearls);
         */

    }
    /* have thread(s) terminate */
    pthread_exit((void*)0);
}

一切都很好看!做出改变,事情看起来很好。如果您发现任何错误,请随时告诉我们!

CODE:

/*******************************************************************************
 *******************************************************************************
 Course: Operating Systems
 Student: Douglas Adolph
 Project: 3, Part 2

 -------------------------------------------------------------------------------
 ///////////////////////////////////////////////////////////////////////////////
 IMPORTANT NOTE:
 ///////////////////////////////////////////////////////////////////////////////
 Some of this code borrows directly from material provided by Dr. Burtscher
 in Texas State University's Parallel Programming course, as well as material
 written by the author (Douglas Adolph) for said parallel programming course.
 ///////////////////////////////////////////////////////////////////////////////
 -------------------------------------------------------------------------------

 -------------------------------------------------------------------------------
 ///////////////////////////////////////////////////////////////////////////////
 SUMMARY:
 ///////////////////////////////////////////////////////////////////////////////
 Program illustrates use of threads and mutual exclusion. N "pirates" (threads)
 complete for 1000 pearls in a cave. Passwords are used to be granted a certain
 percentage of the remaining pearls in the cave. Program should terminate when
 all the pearls have been taken.
 ///////////////////////////////////////////////////////////////////////////////
 -------------------------------------------------------------------------------

 -------------------------------------------------------------------------------
 ///////////////////////////////////////////////////////////////////////////////
 PART 1 AND 2 SPECIFICS:
 ///////////////////////////////////////////////////////////////////////////////
 Part 1: implementation with mutual exclusion NOT considered*
 Part 2: implementation with mutual exclusion considered

 *designed to fail during repeated runtime tests: demonstrate need for exclusion
 *sleep() not used
 ///////////////////////////////////////////////////////////////////////////////
 -------------------------------------------------------------------------------

 -------------------------------------------------------------------------------
 ///////////////////////////////////////////////////////////////////////////////
 THREAD ID, THREAD PASSWORD, AND RESOURCE (PEARLS) RETRIEVAL INFORMATION:
 ///////////////////////////////////////////////////////////////////////////////
 Pirate threads ID'd by rank (i.e. 0, 1, 2, ...), and this rank is used to ID
 which password pirate thread will use. However, in the program output, pirate
 threads are labeled alphanumerically (i.e. A, B, C, ...). However, although
 pirate threads in output are labeled alphanumerically to match professor's
 example, some liberty was taken in the final design of the output.

 Note: if there are more than 26 pirate threads, the implementation of the output
       of total pearls gathered by all pirate threads will need to be changed, or
       labels for all pirate threads after Z will not have reasonable labels

 "Open, sesame:" N/2 pirate processes use this password and
                 receive 10% of the remaining pearls

 "Open, watermelon:" N/2 pirate processes use this password and
                     receive 15% of the remaining pearls

 Even-numbered pirate threads will be assigned password "Open, sesame," where
 password string is represented by 1 (*)

 Odd-numbered pirate threads will be assigned password "Open, watermelon," where
 password string is represented by 0 (*)

 (*) via a modulus operation (thread % 2); string PWs/buffers avoided
 ///////////////////////////////////////////////////////////////////////////////
 -------------------------------------------------------------------------------

 -------------------------------------------------------------------------------
 ///////////////////////////////////////////////////////////////////////////////
 NOTES REGARDING TRANSFER AND EXECUTION OF FILE ON TEXAS STATE SERVERS:
 ///////////////////////////////////////////////////////////////////////////////

 (1) transfer to Zeus for testing effected via:

 scp /Users/douglasadolph/Desktop/School/CourseFolders/OperatingSystems/Projects
 /YourProjects/project3_DouglasAdolph/FILE_NAME da1140@zeus.cs.txstate.edu:

 (2) program compiled via:

 gcc p3_part1_DouglasAdolph.c -o p3p1 -lpthread -lm
 gcc p3_part2_DouglasAdolph.c -o p3p2 -lpthread -lm
 ///////////////////////////////////////////////////////////////////////////////
 -------------------------------------------------------------------------------
 *******************************************************************************
 ******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <math.h>

#define NUM_PIRATE_THREADS 4 /* number of pirate threads to run */
#define OPEN_SESAME 0 /* single bit value representation of password */
#define OPEN_WATERMELON 1 /* single bit value representation of password */

/* percent value for "open, sesame" */
const double OPEN_SESAME_PERCENTAGE = 0.10;

/* percent value for "open, watermelon" */
const double OPEN_WATERMELON_PERCENTAGE = 0.15;

/* array of pirate threads */
static pthread_t *thread_handles;

/* mutual exlusion lock; mutual exclusion considered in this version */
pthread_mutex_t mutex;

/* pirate thread function */
void *pirate(void* rank);

/* total number of items in resource (pearls in the cave) */
static double cavePearls = 1000.00;

/* array to store the number of pearls garnered by each pirate */
int piratesBooty[NUM_PIRATE_THREADS];

/* main function */
int main() {

    /* alert user pirate threads are about to begin consuming pearls */
    printf("\nAvast matey, we are a'comin' fer yee pearls!!\n\n");

    /* index variable for pirate threads */
    long threadIndex;

    /* char variable for pirate thread labeling (i.e. 1, 2, 3, ...) */
    char alphaForPirate = 'A';

    /* create and allocate memory for thread_handles array */
    thread_handles = (pthread_t*)malloc(NUM_PIRATE_THREADS*sizeof(pthread_t));

    /* create and run pirate threads...YAR!*/
    for (threadIndex = 0; threadIndex < NUM_PIRATE_THREADS; ++threadIndex) {
        pthread_create(&thread_handles[threadIndex], NULL,
                       pirate, (void*)threadIndex);
    }

    /* join pirate threads...AVAST MATEY!*/
    for (threadIndex = 0; threadIndex < NUM_PIRATE_THREADS; ++threadIndex) {
        pthread_join(thread_handles[threadIndex], NULL);
    }

    /* update your final cave pearl number to a whole integer value */
    cavePearls = ceil(cavePearls);

    /* display pearl data after pirate thread(s) execution */
    printf("\nYar!! The cave be empty!!\n\n");
    for (threadIndex = 0; threadIndex < NUM_PIRATE_THREADS; ++threadIndex){
        printf("Pirate %c got %d pearls\n",
               alphaForPirate, piratesBooty[threadIndex]);
        alphaForPirate++;
    }
    printf("\n");

    /* free memory */
    free(thread_handles);

    return 0;
} /* end of main() */

void *pirate(void* rank) {

    /* amount of pearls pirate thread(s) may take during current entry to cave */
    static double pearlsToGrab = 0;

    /* variables to output pirate thread(s) pearl consumption */
    char alphaForPirate = 'A';
    int piratePercentage;

    /* label pirate thread(s) alphanumerically */
    alphaForPirate += (long)rank;

    while(1) { /* continue execution while pearls remain in cave */
        if (cavePearls < 1) /* cave has been emptied, pirate thread(s) should stop */
            return 0;

        /* identify which pirate thread you are currently executing */
        long my_rank = (long)rank;

        /* if pirate thread is even: "Open, sesame" pirate */
        if (my_rank % 2 == OPEN_SESAME) {

            /* CRITICAL SECTION LOCKED */
            pthread_mutex_lock(&mutex);

            piratePercentage = (OPEN_SESAME_PERCENTAGE * 100);
            pearlsToGrab = cavePearls * OPEN_SESAME_PERCENTAGE;
            pearlsToGrab = ceil(pearlsToGrab);
            cavePearls = cavePearls - pearlsToGrab;
            piratesBooty[my_rank] += pearlsToGrab;

            printf("Pirate %c gets %.0f of the pearls, %d percent of %.0f pearls available in cave\n",
                   alphaForPirate, pearlsToGrab, piratePercentage, (cavePearls + pearlsToGrab));

            /* CRITICAL SECTION UNLOCKED */
            pthread_mutex_unlock(&mutex);
        }
        /* if pirate thread is odd: "Open, watermelon" pirate */
        else if (my_rank % 2 == OPEN_WATERMELON){

            /* CRITICAL SECTION LOCKED */
            pthread_mutex_lock(&mutex);

            piratePercentage = (OPEN_WATERMELON_PERCENTAGE * 100);
            pearlsToGrab = cavePearls * OPEN_WATERMELON_PERCENTAGE;
            pearlsToGrab = ceil(pearlsToGrab);
            cavePearls = cavePearls - pearlsToGrab;
            piratesBooty[my_rank] += pearlsToGrab;

            printf("Pirate %c gets %.0f of the pearls, %d percent of %.0f pearls available in cave\n",
                   alphaForPirate, pearlsToGrab, piratePercentage, (cavePearls + pearlsToGrab));

            /* CRITICAL SECTION UNLOCKED */
            pthread_mutex_unlock(&mutex);
        }

        /* make pirate thread(s) sleep for 2 seconds */
        sleep(2);

    } /* end of while-loop */

    /* have pirate thread(s) terminate */
    pthread_exit((void*)0);
}

2 个答案:

答案 0 :(得分:2)

在调试器中运行它直到它挂起,然后闯入它并查看状态。我怀疑对于某些执行,cavePearls变为负数,你的线程继续前进。 if (cavePearls == 0)应该是`if(cavePearls&lt; = 0)'。

答案 1 :(得分:2)

至少,此行无效并导致程序具有未定义的行为:

        if (cavePearls == 0) /* cave has been emptied, pirates should stop */

如果没有锁定来对其他线程的访问进行排序,则无法访问共享的可变数据。