簡體   English   中英

Pthreads:如果僅允許在一行代碼中使用互斥鎖,如何使線程安全

[英]Pthreads: How to make thread safe if only allowed to use mutex on one line of code

我有一個作業,其中有4條線進入一個“洞”並取出一定比例的珍珠。 當洞穴中的珍珠耗盡時,線程應停止運轉。 禁止兩個海盜同時“進入洞穴”。

我最初的解決方案運行良好,但是在互斥鎖中包含了大約4行代碼。 我的教授說,我應該只鎖定一行代碼(通過線程將珍珠從洞中取出的那行代碼)。 但是,當我更改代碼以僅保護這一行代碼時,該代碼將不再起作用。 我的打印報表的值不正確,我的總數是錯誤的

有什么方法只能鎖定此行:

cavePearls -= pearlsToGrab;

還有其他人嗎?

據我所知,我必須鎖定多行,否則我將無法打印出正確的數據。

碼:

#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 */
#define SLEEP_TIME 2 /* time for thread to sleep after execution */

/* 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;

/* 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) {
            piratePercentage = (OPEN_SESAME_PERCENTAGE * 100);
            pearlsToGrab = ceil(cavePearls * OPEN_SESAME_PERCENTAGE);

            /*****************************/
            /* CRITICAL SECTION LOCKED */
            pthread_mutex_lock(&mutex);
            cavePearls -= pearlsToGrab;
            piratesBooty[my_rank] += pearlsToGrab;
            /* CRITICAL SECTION UNLOCKED */
            pthread_mutex_unlock(&mutex);
            /*****************************/

            printf("Pirate %c gets %.0f of the pearls, %d percent of %.0f pearls available in cave\n",
                   alphaForPirate, pearlsToGrab, piratePercentage, (cavePearls + pearlsToGrab));
        }
        /* if pirate thread is odd: "Open, watermelon" pirate */
        else if (my_rank % 2 == OPEN_WATERMELON){
            piratePercentage = (OPEN_WATERMELON_PERCENTAGE * 100);
            pearlsToGrab = ceil(cavePearls * OPEN_WATERMELON_PERCENTAGE);

            /*****************************/
            /* CRITICAL SECTION LOCKED */
            pthread_mutex_lock(&mutex);
            cavePearls -= pearlsToGrab;
            piratesBooty[my_rank] += pearlsToGrab;
            /* CRITICAL SECTION UNLOCKED */
            pthread_mutex_unlock(&mutex);
            /*****************************/

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

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

    } /* end of while-loop */

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

更新:

我已經更新了代碼,以將單行包含在互斥鎖中。 它幾乎可以正常工作,但是我遇到了如下競賽情況:

海盜B獲得135顆珍珠,洞穴中900顆珍珠中的15%海盜A獲得100顆珍珠,洞穴C中可用的1000顆珍珠中的10%海盜C獲得77顆珍珠,在洞穴D中可用的765顆珍珠中的10%獲得115顆珍珠,在洞穴中可獲得765顆珍珠的15%

這是更新的代碼:

#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 */
#define SLEEP_TIME 2 /* time for thread to sleep after execution */

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

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

struct PirateBag {
    char alphaForPirate;
    double caveTotal;
    double currentPearlsToTake;
    double takePercentage;
};

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

/* pirate thread pearl removal and update function */
double executeRemoval(int *piratesBooty, struct PirateBag *piratesBag, const long pirate_rank, const double takePercentage, const double cavePearls);

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

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

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

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

/* array to store current pearls being retrieved from cave by pirate thread */
struct PirateBag piratesBag[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 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() */

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

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

    while(1) { /* continue execution while pearls remain in cave */
        if (cavePearls < 1) /* cave has been emptied, pirate thread 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);

            cavePearls -= executeRemoval(piratesBooty, piratesBag, my_rank, OPEN_SESAME_PERCENTAGE, cavePearls);

            /* 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);

            cavePearls -= executeRemoval(piratesBooty, piratesBag, my_rank, OPEN_WATERMELON_PERCENTAGE, cavePearls);

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

        /* print pirate thread data for current entry into the cave */
        printf("Pirate %c gets %d of the pearls, %.f%% of %.0f pearls available in cave\n",
               piratesBag[my_rank].alphaForPirate, (int)piratesBag[my_rank].currentPearlsToTake,
               piratesBag[my_rank].takePercentage, piratesBag[my_rank].caveTotal);

        /* make pirate thread sleep for SLEEP_TIME seconds */
        //sleep(SLEEP_TIME);

    } /* end of while-loop */

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

/* pirate thread pearl removal and collection update function */
double executeRemoval(int *piratesBooty, struct PirateBag *piratesBag, const long pirate_rank, const double takePercentage, const double cavePearls) {
    piratesBooty[pirate_rank] += ceil(cavePearls * takePercentage);
    piratesBag[pirate_rank].alphaForPirate = (pirate_rank + 'A');
    piratesBag[pirate_rank].caveTotal = cavePearls;
    piratesBag[pirate_rank].currentPearlsToTake = ceil(cavePearls * takePercentage);
    piratesBag[pirate_rank].takePercentage = (takePercentage * 100);

    return ceil(cavePearls * takePercentage);
}

這應該足以為您提供線索:

pthread_mutex_lock(&mutex);
cavePerls = perlsToPrint = cavePerls - CalculatePerlsToGrab();
pthread_mutex_unlock(&mutex);
// Print using perlsToPrint value.

注意: CalculatePerlsToGrab()可以是CalcStatsAndReturnPerlsToGrab(&whatever,...)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM