简而言之,此代码有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颗珍珠可以在洞穴中获得答案 0 :(得分:0)
您是否将要打印的值复制到局部变量,并打印副本?
如果您只是将调用移至printf
函数,则还会将共享状态的读取移出临界区。