我是一个初学者,我正在实施餐饮哲学家的问题。然而,我遇到了一个问题。在我的哲学家()函数中,我希望我的其他线程等待,直到左右筷子都可以使用。我应该如何实现这一点?目前,该计划只是在两位哲学家吃完后终止,而不等待其他人吃完
我已经试过了:
任何帮助都很感激,谢谢!
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#define NUM 5 // Number of Philosophers
sem_t chopSticks[NUM]; // binary semaphore for each chopstick
sem_t mutex;
int philNo[NUM] = {0, 1, 2, 3, 4};
void* philosopher(void*);
int main()
{
int semValue;
pthread_t threadId[NUM]; // 5 concurrent threads for 5 philsophers
sem_init(&mutex, 0, 1);
for(int i=0; i< NUM; i++)
sem_init(&chopSticks[i], 0, 1);
for(int i=0; i< NUM; i++)
{
pthread_create(&threadId[i], NULL, philosopher, (void*) &philNo[i]);
printf("\nPhilosopher %d is thinking", i+1);
}
for(int i=0; i< NUM; i++)
pthread_join(threadId[i], NULL);
return 0;
}
void* philosopher(void* philNo)
{
int n = *(int*) philNo;
int rightValue, leftValue;
int left = (n+4) % NUM;
int right = (n+1) % NUM;
sem_getvalue(&chopSticks[left], &leftValue);
sem_getvalue(&chopSticks[right], &rightValue);
//sem_wait(&mutex);
/* while(leftValue != 1 && rightValue != 1)
{
wait for the left and right chopsticks to be free
How should I implement this?
} */
if(leftValue == 1 && rightValue == 1) // if both left and right chopSticks are free then start eating
{
sem_wait(&chopSticks[left]);
sem_wait(&chopSticks[right]);
printf("\nPhilosopher %d has taken Chopstick-%d and Chopstick-%d", n+1, left+1, right+1);
printf("\nPhilosopher %d is Eating", n+1);
sleep(1);
sem_post(&chopSticks[left]);
sem_post(&chopSticks[right]);
printf("\nPhilosopher %d finished eating", n+1);
printf("\nPhilosopher %d has put down chopstick-%d and chopstick-%d", n+1, left+1, right+1);
}
//sem_post(&mutex);
}
我是一个初学者,我正在解决哲学家的问题。然而,我遇到了一个问题。在我的哲学家()函数中,我希望我的其他线程等待,直到左右筷子都可以使用。我应该如何实现这一点?
我已经试过了:
您绝对需要至少一个互斥锁或类似的同步对象,因为您的线程需要访问共享数据(筷子的状态或等效的)。只能在受适当同步对象保护的关键部分访问共享数据。
然而,您不一定需要在这些访问之间锁定互斥锁,并且通常希望避免这样做,以便其他线程有机会运行。
正如我在评论中所写,sleep()
不是一个同步函数。它可能在html" target="_blank">解决方案中起作用,但在线程间活动中不起作用。
对于哲学家进餐问题,需要认识到的关键是,如果你想让哲学家同时进餐,而不必安排整个进餐的细节,那么每个哲学家必须能够多次尝试拿起筷子,直到他们成功,同时不妨碍任何其他哲学家进餐。
此外,当线程没有理由认为自上次尝试以来发生了任何变化时,一遍又一遍地尝试会适得其反。
当线程需要等待,直到满足某些依赖于数据的条件时,应立即考虑使用条件变量。有时有合理的选择,但条件变量是这些情况下的瑞士军刀。
条件变量与互斥体一起使用--互斥体用于保护非原子变量,每个线程将通过这些变量确定是否可以继续,如果线程确定它必须等待,CV将帮助它允许其他线程在等待时锁定互斥体,并在收到通知,它应该再次检查。这应该总是在循环中执行,因为线程可能会在唤醒后确定条件仍然不适合它向前移动。
有几种方法可以在问题中实现这一点。您可以为每个筷子使用单独的条件变量,所有筷子都具有相同的互斥体,但只使用一个互斥体和一个CV会更简单:
>
当其中一位哲学家决定他可以吃饭时,他会锁定互斥锁,并检查他需要的两支筷子是否都有。
>
如果是这样,他拿起它们,释放互斥,然后继续吃。
如果没有,则等待另一个线程通知条件变量。在此等待期间,互斥锁将自动释放,并在线程从互斥锁恢复之前重新获得互斥锁。当线程恢复时,它会循环回去再次检查筷子。
例如(为了清楚起见,省略了错误检查):
pthread_mutex_lock(&mutex);
while(chopsticks[left] || chopsticks[right]) {
pthread_cond_wait(&cv, &mutex);
}
chopsticks[left] = 1;
chopsticks[right] = 1;
pthread_mutex_unlock(&mutex);
当哲学家吃完后,他锁上互斥锁,放下筷子,释放互斥锁,然后向所有等待简历的线程发出信号,这样他们就会再次检查他们是否可以继续。
例如:
pthread_mutex_lock(&mutex);
chopsticks[left] = 0;
chopsticks[right] = 0;
pthread_mutex_unlock(&mutex);
pthread_cond_broadcast(&cv);
还要注意的是,由于筷子状态是通过互斥来保护的,因此使用信号量对其进行建模没有任何好处。上面的示例代码假设一个普通的\u Bool
数组或其他一些整数类型,用全零初始化。
你不能在餐桌上吃叉子。这是将导致你陷入僵局的经典错误。想象一下,所有的哲学家同时拿起左分叉,你的Sempahore实现将允许这样做,但是在那之后,没有人能够拿起右分叉,因为没有一个是可用的,所有的线程都将无限期地阻塞。
只有当两个叉子都能起作用时,这两个叉子才会起作用
哲人的套路是:0。每个哲学家都会有与她相关的状态。国家由邻居介绍,以了解哲学家在做什么。
伪oop代码如下:
#define N 5
#define LEFT(i) (i-1)%N
#define RIGHT(i) (i+1)%N
#define THINKING 0
#define HUNGRY 1
#define EATING 2
class DinningPhilosopher {
public:
DinningPhilosopher();
~DinningPhilosopher();
void
philosopherRoutine(
IN byte i
);
private:
byte m_state[N];
Semaphore *m_sem[N];
Mutex *m_mutex;
void
takeForks(
IN byte i
);
void
putForks(
IN byte i
);
void
testForkAvailability(
IN byte i
);
};
DinningPhilosopher::DinningPhilosopher()
{
// All philosopher's are thinking initially.
for (int i=0; i<N; i++) {
m_state[i] = THINKING;
}
for (int i=0; i<N; i++) {
m_sem[i] = new Semaphore(0);
}
m_mutex = new Mutex();
}
// N threads will be spawned, one for each philosopher.
// Argument i is philosopher id between (0,N)
void
DinningPhilosopher::philosopherRoutine(
IN byte i
)
{
while(true) {
continueThinking();
takeForks(i);
continueEating();
putForks(i);
}
}
void
DinningPhilosopher::takeForks(
IN byte i
)
{
m_mutex->lock();
// Announce to neighbours you're HUNGRY.
m_state[i] = HUNGRY;
// Test if left fork & right forks are available.
// If available announce neighbours you're EATING.
// so they don't pick up forks you already claimed.
testForkAvailability(i);
m_mutex->unlock();
// If you are not yet EATING,
// block till required forks are available.
// Section A.
m_sem[i]->wait();
}
void
DinningPhilosopher::testForkAvailability(
IN byte i
)
{
// Note that m_mutex was locked before calling this function
// Thread has exclusive access to execute this function.
if (m_state[LEFT(i)] != EATING && // your left fork is available
m_state[RIGHT(i)] != EATING && // your right fork is available
m_state[i] == HUNGRY // and you want to start eating.
) {
// Announce neighbours you started eating.
m_state[i] = EATING;
// Fork availability is passed.
// Make sure you're not blocked at "Section A"
// in function takeForks()
m_sem[i]->post();
}
}
void
DinningPhilosopher::putForks(
IN byte i
)
{
m_mutex->lock();
// Announce to neighbours you're done EATING.
m_state[i] = THINKING;
// Put down the left fork,
// If your left neighbour is blocked at "Section A"
// of function takeForks().
// Allow him to unblock to start eating.
testAvailability(LEFT(i));
// Put down the right fork.
testAvailability(RIGHT(i));
m_mutex->unlock();
}
查看下面的链接:https://codeistry.wordpress.com/2018/04/06/dinning-philosophers-problem/
如果一个线程已经获取了锁,我希望其他线程跳过获取锁的尝试,只需等待释放锁,然后再继续执行。我不希望其他线程在释放锁后获取它。 我一直在研究这个问题,但仍然感到困惑。 请参阅以下通用代码段: 我怎么能让线程进入我的其他块等待重入锁被解锁之前继续执行?
这里的要点是了解实现等待循环的更有效的解决方案,该循环在每次迭代时轮询条件。通过高效,我的意思是“有效的CPU调度”。 我知道代码中使用的等待条件不是“wakeOne”/“wakeAll”指令中使用的“真正的等待条件”,但我想知道对CPU来说,使用假等待条件是否比睡眠更有效。 这里有2个代码片段,它们做同样的事情:等待某些事情发生。这段代码用于工作线程池。因此,当一个线程等待时,其他线程(或其他一
我打算在主线程中启动2个线程,主线程应该等到所有2个子线程完成,我就是这样做的。 在上面的代码中,确实让主线程等待子线程,但问题是,在第一个线程完成之前不会创建第二个线程。这不是我想要的。 我想要的是,这两个线程立即在主线程中创建,然后主线程等待它们完成。似乎做不到,是吗? 我想,也许我可以通过一个信号灯来完成这项工作,但还有别的方法吗?
有时我看到一些线程还没有完成他们的工作,服务杀死那个线程,我怎么能强迫服务等待,直到线程完成他们的工作? 这是我的代码: 我看到了一些例外。future.is完成())块。我怎么能确保每一个未来是当执行者服务关闭?
问题内容: 在这里,我想每秒钟调用一次“ Log.d”和“ postInvalidate”。但是,当我从LogCat检查它时,似乎循环运行的速度比我希望的要快。为什么这个循环不等待1000ms? 以下是LogCat中的输出。因此,您可以看到它根本没有休眠1秒钟。我也使用了Thread.sleep(在您建议之后) 这是最新的代码。是布尔值,现在是事实。 输出是 问题答案: 您需要类的方法。 使发送此
问题内容: 我正在为我的ubuntu服务器(针对我的多客户端匿名聊天程序)实现一种简单的线程池机制,并且需要使我的工作线程进入睡眠状态,直到需要执行一项工作(以函数指针和参数的形式) 。 我当前的系统即将关闭。我(工人线程正在)问经理是否有工作可用,以及是否有5毫秒没有睡眠。如果存在,请将作业添加到工作队列中并运行该函数。糟糕的循环浪费。 什么我 喜欢 做的是做一个简单的事件性的系统。我正在考虑有