【问题标题】:C, rand function doesn't work properly with sleep() function [closed]C,rand 函数不能与 sleep() 函数一起正常工作 [关闭]
【发布时间】:2016-07-13 19:28:42
【问题描述】:

首先,我知道有很多关于 rand() 函数的问题,但我认为这是不同的。

实际上,当我没有与 sleep() 函数结合时,rand() 函数总是可以正常工作。我尝试过这个。但是当我像这样“sleep(rand() %5)”将 rand() 函数与 sleep() 结合使用时,有时它会为所有子进程产生随机时间,如我所料,但有时对前 4-5 个孩子效果很好,之后,它为所有剩余的子进程生成 0。所以其他子进程不会休眠。有时它总是为所有子进程生成 0。

顺便说一句,我在 Ubuntu 64 位上编码。

关于我的代码: 我想从父进程中分叉 8 个子进程并一一打印他们的 pid 号。但是我应该在创建一个孩子后使用睡眠功能。睡眠时间应该是随机的。我使用 time() 函数作为种子并尝试使用 rand 函数,但它不能与 sleep 函数一起正常工作。

这是我的代码:

#include <stdio.h>
#include <sys/sem.h>
#include <unistd.h>
#include <wait.h>
#include <stdlib.h>
#include <time.h>


void childs();
void parent();


int id;
int i;
int pidID[9];
int fd[2];
char buff[100];
int main(int argc, char *argv[]){
    pid_t child;
    for(i = 0; i < 8; i++){
        pipe(fd);

        child = fork();
        wait(NULL);
        if(child){
            parent();
            continue;
        }else if(child == 0){
            childs();
            break;
        }else{
            perror("State\n");
            exit(1);
        }
    }
    if(child ==0){
    printf("I am a child pid: %d, ppid: %d pidno: %d\n", getpid(), getppid(),pidID[i+1]);
    }else{
    printf("I am a parent pid: %d, ppid: %d pidno: %d\n", getpid(), getppid(),pidID[0]);
    }

}


void childs(){
id = getpid();
pidID[i + 1] = id;
char swap[50];
sprintf(swap, "%d" ,id);
write(fd[1], swap, 10);
srand(time(NULL));
int randomTime = rand() %5;
printf("Random time: %d\n",randomTime);
sleep(randomTime);
}



void parent(){
pidID[0] = getpid();
read(fd[0], buff , 10);
printf("Buff: %s\n", buff);
}

【问题讨论】:

  • 定义“运作良好”的含义和“成为0 ...”的含义。
  • 我的意思是有时 rand() 产品随机数,正如我所料。但有时它只产生 0。我现在将编辑问题。
  • 正确格式化和缩进你的代码。并且标准不推荐使用非原型函数声明符。不要使用它们。
  • 从当前时间播种随机数生成器永远不会正确。你能说的最好的就是偶尔它是无害的。
  • @rici 我应该用什么来代替时间作为种子?你有什么建议?

标签: c random sleep


【解决方案1】:

当您在每个子进程中 srandtime(NULL) 时,在同一秒内启动的所有子进程都将使用相同的值作为种子。

当然,在涉及sleepwait 的情况下,如果孩子sleep 一秒钟,他们就会播种一个新的值,所以如果你一直在睡觉,事情就会很顺利。

rand() % 5 产生的值介于 0 和 4 之间;第一次给定的time 种子将导致第一个rand() 输出为5 的倍数,您休眠0 秒,子进程几乎立即退出,循环分叉一个新子进程,所有这些都在a最多几毫秒。并且它会持续执行此操作一秒(或更长时间),直到 time reseed 将 rand 的第一个输出更改为不是 5 的倍数的值。

如果你想解决这个问题,最简单(如果仍然很傻)的方法是改变:

int randomTime = rand() %5;

到:

int randomTime = rand() %5 + 1; // Range 1-5, or use rand() % 4 + 1 for 1-4

因此,您的睡眠时间永远不会少于一秒,并且您永远不会陷入不断重新播种的病态情况,即一遍又一遍地产生相同的零秒睡眠。

或者,如果零秒睡眠必须是可能的,则使用更细粒度的time 函数来获得变化更快的种子。例如,在 POSIX 系统上,您可能会改用 clock_gettime,它应该变化得更快:

struct timespec tm;
clock_gettime(CLOCK_MONOTONIC, &tm);
// xor-ing with tv_nsec >> 31 to ensure even low precision clocks vary
// the low 32 bits
srand((unsigned)(tm.tv_sec ^ tm.tv_nsec ^ (tm.tv_nsec >> 31)));

您可以继续使用rand() % 5,因为srands 之间的时间应该足够长,可以更改tv_nsec 中的一些值并获得不同的种子值。

【讨论】:

  • 有道理。非常感谢!
  • 以下是对每个孩子进行不同播种的建议 - 在 pid 中混合:stackoverflow.com/a/8623196/12711
  • @MichaelBurr:好点子。尽管从技术上讲,由于每个孩子在下一次启动之前退出,因此无法保证一个奇怪的系统不会一遍又一遍地重新发布相同的 PID(实际上,我见过的每个系统都会循环,所以它不会重新发布,直到所有未使用的 PID 都已发布一次,但我认为这不是强制性的,因此病态系统可能会搞砸你)。如果你有很多孩子同时跑步,那无论如何都行得通。
  • 您可以从 fork 子代的循环中混入 i
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多