哲学家问题 POSIX 信号量

学习了使用POSIX信号量来解决哲学家问题,代码及注释如下:

/** @file      philosopher_thread.c
 *  @brief     模拟哲学家思考和吃饭问题
 *  @note      
 *  @author
 *  @date
 *  @version   v1.0
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>

#define PHL_DEBUG
#ifdef PHL_DEBUG
#define PHL_PRT(...) do{printf("[%s]",__func__);printf(""__VA_ARGS__);}while(0)
#else
#define PHL_PRT(...)
#endif


#define PHILOSHOPHER_NUM   5

sem_t fork_num[PHILOSHOPHER_NUM];

/**@fn           void think_random_time()
 * @brief        随机数生成模拟哲学家思考吃饭过程
 * @return       无
 */
void think_eat_random_time()
{
    int time;
    time = rand()%PHILOSHOPHER_NUM + 1;               // 思考时间,1 ~ 5
    printf("time = %d s\n", time);
    sleep(time);
}


/**@fn           void* philosopher_think_eat(void *arg)
 * @brief        模拟哲学家的思考和吃饭过程
 * @param        void *arg  表示第几个哲学家
 * @note         具体过程是首先一个哲学家判断左右手是否可以获取叉子,如果有的话则获取
                 叉子,如果是两只手都有叉子,则开始吃饭,如果是一只手获取,则再等待
                 1 s 后查看另一只手是否能够获取叉子,能够的话获取吃饭,否则释放掉自己
                 手中的叉子,思考
 * @return       无
 */
void* philosopher_think_eat(void *arg)
{
    int i = *((int *)arg);

    // 定义左右手变量来表示哲学家左右手的叉子
    int lefthand = (i-1+PHILOSHOPHER_NUM)%PHILOSHOPHER_NUM;             
    int righthand = i;

    // 定义一下变量表示哲学家获取左右手叉子是否成功
    int leftOK = 0;
    int rightOK = 0;
    
    while (1)
    {
        PHL_PRT("philosopher %d is going to think ", i);
        think_eat_random_time();

        // 获取左右手的叉子
        leftOK = sem_trywait( &fork_num[lefthand] );
        rightOK = sem_trywait( &fork_num[righthand] );

        /*  哲学家通过获取左右手的叉子来判断是否可以吃饭   */
        if ( 0 == (leftOK || rightOK) )    // 都为 0 表示 OK ,可以吃饭
        {
            printf("philosopher %d going to eat ", i);
            think_eat_random_time();

            // 释放左右手叉子
            sem_post(&fork_num[lefthand]);
            sem_post(&fork_num[righthand]);
        }

        else if ( 0 == leftOK)             // 左手获取了叉子,等待 1 s,判断右手看是否有叉子
        {
            sleep(1);
            rightOK = sem_trywait( &fork_num[righthand] );  // 再次获取右手叉子
            if ( 0 == rightOK )                          // 获取成功
            {
                printf("philosopher %d going to eat ", i);
                think_eat_random_time();

                // 释放左右手叉子
                sem_post(&fork_num[lefthand]);
                sem_post(&fork_num[righthand]);
                
            }
            
        }
        else if ( 0 == rightOK )           // 左手获取了叉子,等待 1 s,判断右手看是否有叉子
        {
            sleep(1);
            leftOK = sem_trywait( &fork_num[lefthand] );    // 再次获取右手叉子
            if ( 0 == leftOK )                           // 获取成功
            {
                printf("philosopher %d going to eat ", i);
                think_eat_random_time();

                // 释放左右手叉子
                sem_post(&fork_num[lefthand]);
                sem_post(&fork_num[righthand]);
                
            }
    
        }
        else  // 表示左右手都没有获得叉子,直接进入思考
        {
            continue;
        }
        
    }

    
    

}


/**@fn           void philosopher( int i )
 * @brief        创建 i 个哲学家并模拟吃通心粉和思考过程
 * @param        int i;  传入的哲学家个数
 * @return       无
 */
void philosopher( int i )
{
    int num = i;
    int j = 0, k = 0;
    pthread_t td[num];
    int err[num];   

    int tmp = 0;

    for ( j=0; j<num; j++ )
    {
        err[j] = pthread_create(&td[j], NULL, philosopher_think_eat, &j);
        if ( err[j] < 0 )
        {
            perror("philosopher create error!\n");
            for ( k=0; k<PHILOSHOPHER_NUM; k++ )          
            {
                if ( sem_destroy(&fork_num[k]) < 0 )    // 删除信号量
                {
                    perror("sem_init error!\n");
                    exit (-1);
                }
            }
            exit( -1 );
        }
        tmp ++;
        usleep(100);        // 睡眠100ms是为了防止创建的线程传入的 j 值都一样
    }
    
}





/**@fn           int main(int argc, char* argv[])
 * @brief        函数入口
 * @param        无
 * @return       0-true,-1-false
 */
int main(int argc, char* argv[])
{
    int i = 0;

    srand((unsigned)time(NULL));    // 种下时间种子,产生随机数表示哲学家的思考和吃饭时间

    for ( i=0; i<PHILOSHOPHER_NUM; i++ )          
    {
        if ( sem_init(&fork_num[i], 0, 1) < 0 )   // 初始化信号量为 1,且共享
        {
            perror("sem_init error!\n");
            exit (-1);
        }
    }
    
    philosopher(PHILOSHOPHER_NUM);                 // 调用函数模拟思考吃饭过程


    while (1)
    {
        printf("----------1s passed-------------\n");
        sleep(1);                                 // 主函数睡眠
    }

    for ( i=0; i<PHILOSHOPHER_NUM; i++ )          
    {
        if ( sem_destroy(&fork_num[i]) < 0 )    // 初始化信号量为 1,且共享
        {
            perror("sem_init error!\n");
            exit (-1);
        }
    }


    return 0;
}











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值