[英]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.