【问题标题】:POSIX semaphore with related processes running threadsPOSIX 信号量与相关进程运行线程
【发布时间】:2014-05-04 02:34:19
【问题描述】:

我有一个任务以复杂的方式实现生产者消费者问题(可能是为了测试我的理解)。父进程应该设置共享内存。应初始化未命名的信号量(用于空计数和填充计数),并应初始化互斥锁。然后创建两个子进程,一个生产者子进程和一个消费者子进程。每个子进程都应该创建一个新线程来完成这项工作。

PS:我已经读过信号量应该保存在共享内存中,因为它们将由不同的进程共享。

请提供一些提示,或提出更改建议。

到目前为止,我已经这样做了:

struct shmarea 
{
unsigned short int read;
unsigned short int max_size;
char scratch[3][50];
unsigned short int write;
sem_t sem1;// Empty slot semaphore
sem_t sem2;// Filled slot Semaphore
}; 

void *thread_read(void* args);
void *thread_write(void *args);

pthread_mutex_t work_mutex;

struct shmarea *shma;

int main()
{
int fork_value,i=0,shmid;
printf("Parent process id is %d\n\n",getpid());
int res1,res2;
key_t key;
char *path = "/tmp";
int id = 'S';

key = ftok(path, id);
shmid =  shmget(key,getpagesize(),IPC_CREAT|0666);

printf("Parent:Shared Memory id = %d\n",id);
shma = shmat(shmid,0,0);    

shma->read = 0;
shma->max_size = 3;
shma->write = 0; 

pthread_t a_thread;
pthread_t b_thread;

void *thread_result1,*thread_result2;

res1 = sem_init(&(shma->sem1),1,3);//Initializing empty slot sempahore
res2 = sem_init(&(shma->sem2),1,0);//Initializing filled slot sempahore

res1 = pthread_mutex_init(&work_mutex,NULL);

while(i<2)
{
    fork_value = fork();
    if(fork_value > 0)
    {
        i++;
    }
    if(fork_value == 0)
    {
        if(i==0)
        {           
            printf("***0***\n");
            //sem_t sem1temp = shma->sem1;
            char ch;int res;
            res= pthread_create(&a_thread,NULL,thread_write,NULL);
        }
        if(i==1)
        {
            printf("***1***\n");        
            //sem_t sem2temp = shma->sem2;      
            int res;
            char ch;
            res= pthread_create(&b_thread,NULL,thread_read,NULL);
        }
    }
}
int wait_V,status;
res1 = pthread_join(a_thread,&thread_result1);
res2 = pthread_join(b_thread,&thread_result2);
}

void *thread_read(void *args)
{   
    while(1)
    {
        sem_wait(&(shma->sem2));
        pthread_mutex_lock(&work_mutex);
        printf("The buf read from consumer:%s\n",shma->scratch[shma->read]);
        shma->read = (shma->read+1)%shma->max_size;             
        pthread_mutex_unlock(&work_mutex);
        sem_post(&(shma->sem1));
    }
} 

void *thread_write(void *args)
{
    char buf[50];
    while(1)
    {
        sem_wait(&(shma->sem1));    
        pthread_mutex_lock(&work_mutex);
        read(STDIN_FILENO,buf,sizeof(buf)); 
        strcpy(shma->scratch[shma->write],buf);
        shma->write = (shma->write+1)%shma->max_size;               
        pthread_mutex_unlock(&work_mutex);
        sem_post(&(shma->sem2));
    }
} 

【问题讨论】:

    标签: linux pthreads posix mutex semaphore


    【解决方案1】:

    (1) 到目前为止,您最大的问题是您设法编写了一个 fork 炸弹。因为您不会在 fork 循环中退出任何一个孩子,所以每个孩子都会跌倒并循环并创建自己的孩子,直到您崩溃或系统崩溃。你想要更多这样的东西:

    while(i < 2)
    {
        fork_value = fork();
    
        if(fork_value > 0)
            i++;
    
        if(fork_value == 0)
        {
            if(i==0)
            {
                printf("0 child is pid %d\n", getpid());
    
                int res;
                res = pthread_create(&a_thread,NULL,thread_write,NULL);
                res = pthread_join(a_thread,&thread_result1);
                exit(0);
            }
    
            if(i==1)
            {
                printf("1 child is pid %d\n", getpid());
    
                int res;
                res = pthread_create(&b_thread,NULL,thread_read,NULL);
                res = pthread_join(b_thread,&thread_result2);
                exit(0);
            }
        }
    }
    
    for (i = 0; i < 2; ++i)
        wait(NULL);
    

    请注意您忽略的孩子的wait

    (2) 始终检查您的返回代码。它们就像安全带,有点拖累,但在你撞车时很有帮助。 (是的,我没有在这里接受我的建议,但你应该接受。)

    (3) 这些名字很糟糕。

    unsigned short int read;
    unsigned short int write;
    

    避免在系统调用后命名变量。这很令人困惑,只是自找麻烦。

    (4) 在术语方面,具有共同祖先的进程(例如这些)是相关的。父母可以打开共享内存和其他资源并将其传递给孩子。例如,不相关的进程将是从不同终端启动的多个程序实例。它们可以共享资源,但不能以分叉进程的“继承”方式共享。

    已经很晚了,没有时间查看你在用线程做什么,但这应该让你开始。

    【讨论】:

    • 感谢 cmets 的帮助。在发布问题时,我省略了清理代码。叉子炸弹确实是失败的根本原因。我把这些线和我的程序工作:) 所以我有几个疑问 1.为什么我们必须把信号量放在共享内存中,即使它们是相关的进程,根据你在第 4 点中所说的术语。因为它们是相关的不是全局变量,信号量会自动映射到子进程和线程。如果我不在 shm mem 中保留信号量,并将它们作为全局变量保留,会有问题吗?
    • 这里有一个皱纹可能会让你感到困惑。首先让我们确定一个孩子从父母那里继承了一堆东西文件描述符,共享内存段等。但它只获得程序内存的副本,例如堆栈、代码、堆等。因此,在分叉之后,子级或父级对该内存所做的任何更改都不会相互影响。现在 POSIX 有 2 个信号量家族,sysV 和新的“posix”信号量(尽管 both 都是 POSIX 的一部分)。内核自己管理 SysV 信号量的数据; posix 信号量将信息保存在用户空间中。所以如果使用 sysV sems 你
    • 不需要共享内存。您将在父级中拥有一个 semid 的副本、已与内核建立的权限等。在这种情况下,copy 可以正常工作,因为它(在概念上)就像指向内核中某物的指针。 Posix sem,OTOH,将 sem_t 数据保存在用户空间中。这个数据会随着每个与信号量相关的系统调用而改变。如果将其保存在正常(非共享)进程内存中,则父子进程将在单独的副本上运行 - 可预见的不良结果。您正在使用 Posix 信号量,因此您必须使用共享内存。
    • 他们是,顺便说一句,使用 sysV 共享内存(就像你正在做的那样)和 posix 信号量没有错。知道 IPC 的两个系列的行为略有不同是很有用的。
    • 非常感谢@Duck 的详细解释。我你不介意,将来会标记你对 SO 的一些疑问。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多