Java-操作系统-5

1.18 介绍一下信号量。

参考回答

  1. 在多进程环境下,为了防止多个进程同时访问一个公共资源而出现问题,需要一种方法来协调各个进程,保证它们能够合理地使用公共资源。信号量就是这样一种机制。

    信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:  

    extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));  

    sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。  

    (1)函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。  

    (2)函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。  

    (3)函数sem_timedwait(sem_t *sem, const struct timespec *abs_timeout) 与 sem_wait() 类似,只不过 abs_timeout 指定一个阻塞的时间上限,如果调用因不能立即执行递减而要阻塞。

    (4)函数sem_destroy(sem_t *sem)用来释放信号量sem。 

  2. 使用示例代码如下

//g++ semtest.cpp -o test -lpthread
#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>
sem_t sem;

/*function:获取当前时间,精确到毫秒
 * */
int64_t getTimeMsec()
{
    struct  timeval    tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

void* func_sem_wait(void* arg)
{
    printf("set wait\n");
    sem_wait(&sem);
    printf("sem wait success\n");
    int *running = (int*)arg;
    printf("func_sem_wait running\n");
    printf("%d\n", *running);
}

void* func_sem_timedwait(void* arg)
{
    timespec timewait;
    timewait.tv_sec = getTimeMsec() / 1000 + 2;
    timewait.tv_nsec = 0;
    printf("sem_timedwait\n");
    int ret = sem_timedwait(&sem, &timewait);
    printf("sem_timedwait,ret=%d\n", ret);
    printf("func_sem_timedwait running\n");
}

void* func_sem_post(void* arg)
{
    printf("func_sem_post running\n");
    printf("sem post\n");
    int *a = (int*)arg;
    *a = 6;
    sem_post(&sem);
    sem_post(&sem);
}

int main()
{
    sem_init(&sem, 0, 0);
    pthread_t thread[3];
    int a = 5;

    pthread_create(&(thread[0]), NULL, func_sem_wait, &a);
    printf("thread func_sem_wait\n");

    pthread_create(&(thread[2]), NULL, func_sem_timedwait, &a);
    printf("thread func_sem_timedwait\n");

    sleep(4);

    pthread_create(&(thread[1]), NULL, func_sem_post, &a);
    printf("thread func_sem_post\n");

    pthread_join(thread[0], NULL);
    pthread_join(thread[1], NULL);
    pthread_join(thread[2], NULL);
    sem_destroy(&sem);
}

1.19 说说僵尸进程和孤儿进程。

参考回答

  1. 我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。

  2. 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

  3. 僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程。

1.20 请介绍进程之间的通信方式。

参考回答

进程间通信主要有以下几种方式

  1. 管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/wait.h>
    
    int pipe_default[2];
    
    int main()
    {
    pid_t pid;
    char buffer[32];
    
    memset(buffer, 0, 32);
    if(pipe(pipe_default) < 0)
    {
      printf("Failed to create pipe!\n");
      return 0;
    }
    
    if(0 == (pid = fork()))
    {
      close(pipe_default[1]); //关闭写端
      sleep(2);
      if(read(pipe_default[0], buffer, 32) > 0)
      {
        printf("[Client] Receive data from server: %s \n", buffer);
      }
      close(pipe_default[0]);
     }
    else
    {
      close(pipe_default[0]);  //关闭读端
      char msg[32]="== hello world ==";
      if(-1 != write(pipe_default[1], msg, strlen(msg)))
      {
        printf("[Server] Send data to client: %s \n",msg);
      }
      close(pipe_default[1]);
      waitpid(pid, NULL, 0);
    }
    return 1;
    }
  2. 命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

    写管道:

    #include <stdio.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <string.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    
    int main()
    {
        int nFd = 0;
        int nWrLen = 0, nReadLen = 0;;
        char szBuff[BUFSIZ] = {0};
    
        /* 打开当前目录下的管道文件 */
        nFd = open("pipe", O_RDWR);
        if (-1 == nFd)
        {
            perror("Open fifo failed\n");
            return 1;
        }
    
        while (1)
        {
            /* 从终端读取数据 */
            memset(szBuff,0,BUFSIZ);
            nReadLen = read(STDIN_FILENO,szBuff,BUFSIZ);
    
            if(nReadLen > 0)
            {
                /* 往管道写入数据 */
                nWrLen = write(nFd, szBuff, strlen(szBuff)+1);
                if (nWrLen > 0)
                {
                    printf("write data successful: %s \n", szBuff);
                }
                else
                {
                    perror("write failed:");
                }
            }
        }
    }

读管道:

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>

int main()
{
    int nFd = 0;
    int  nReadLen = 0;;
    char szBuff[BUFSIZ] = {0};

    /* 打开当前目录下的管道文件 */
    nFd = open("pipe", O_RDWR);
    if (-1 == nFd)
    {
        perror("Open fifo failed\n");
        return 1;
    }

    while (1)

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Java岗位面试真题宝典 文章被收录于专栏

本面试宝典均来自校招面试题目大数据进行的整理

全部评论

相关推荐

哞客37422655...:你猜为什么福利这么好还得一直追着你问
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务