Pthreads:无法将我的print语句放在我的互斥锁之外并成功运行。有没有办法影响这个?

时间:2017-11-05 02:50:19

标签: c pthreads mutex

简而言之,此代码有4个线程在洞穴中竞争珍珠。他们应该将珍珠从洞穴中取出,一次一个,并在洞穴耗尽时停止。

当我在互斥锁中使用printf()时,我的代码运行得很好,但是当我取出它时,我得到错误的打印输出数据(尽管代码完成后最终值是正确的)。

我创建了一个特定于每个线程ID的结构(因此那里没有竞争条件)所以我可以在每个线程执行后更新并以这种方式访问​​printf()中的数据。此结构中的数据是正确的,但它是如何在printf语句中访问它导致问题。 printf()语句使用my_rank打印正确的数据。当我将此printf()移出锁定时,运行时信息是错误的,因为(某种程度上)线程B进入两次并打印相同的数据两次。

代码:

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

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

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

        /* cave has been emptied, pirate thread should stop */
        if (cavePearls < 1)
            return 0;

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

        /* remove the correct number of pearls from the cave */
        cavePearls -= executeRemoval(piratesBooty, piratesBag, my_rank, cavePearls);

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

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

    } /* 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 cavePearls) {

    /* cave has been emptied, pirate thread should stop */
    if (cavePearls < 1)
        return 0;

    /* variable to capture correct pirate thread percentage of pearls to take */
    double takePercentVal;

    /* identify correct pirate thread percentage */
    if (pirate_rank % 2 == OPEN_SESAME)
        takePercentVal = OPEN_SESAME_PERCENTAGE;
    else takePercentVal = OPEN_WATERMELON_PERCENTAGE;

    /* update data for pirate thread */
    piratesBooty[pirate_rank] += ceil(cavePearls * takePercentVal);
    piratesBag[pirate_rank].alphaForPirate = (pirate_rank + 'A');
    piratesBag[pirate_rank].caveTotal = cavePearls;
    piratesBag[pirate_rank].currentPearlsToTake = ceil(cavePearls * takePercentVal);
    piratesBag[pirate_rank].takePercentage = (takePercentVal * 100);

    /* return number of pearls pirate thread should take */
    return ceil(cavePearls * takePercentVal);
}

这是我将printf()移出锁定时的运行时错误:

海盗A获得100颗珍珠,10%的珍珠可以在洞穴中获得

海盗B获得了135颗珍珠,其中15%的珍珠可以在洞穴中获得

海盗B获得了135颗珍珠,其中15%的珍珠可以在洞穴中获得

海盗D获得了115颗珍珠,15%的765颗珍珠可以在洞穴中获得

1 个答案:

答案 0 :(得分:0)

您是否将要打印的值复制到局部变量,并打印副本?

如果您只是将调用移至printf函数,则还会将共享状态的读取移出临界区。