多线程之Job queue实验(六)

原创 2018年02月09日 20:48:47

1. 题目

what additional synchronization (if any) is necessary to allow the master thread to change the thread ID associated with a pending job? and use variable condition to complete the worker function of this queue.

主要API展示:


int queue_init(struct queue *qp)
{
....
}

void job_insert(struct queue *qp, struct job *jp)
{
.....
}

void job_remove(struct queue *qp, struct job *jp)
{
.....
}

struct job * job_find(struct queue *qp, pthread_t id)
{
.....
}

2. 审题

  本题由单向链表构成的job queue,在这里笔者假设该job queue 具有9个节点,也就是job。 分别由3个子线程去获得与自己Thread ID 对应的job,在运行过程中,由主线程修改job queue 中的最后一个jobThread ID 从而使其不属于任何线程。
  
2.1 竞态分析:

  • 如果我们希望find_job,之后再去job_remove,那么会有可能在find_job之后该jobThread ID 被主线程修改。从而造成job_remove不属于该线程的job。
  • 子线程和主线程的同步是个难题,如果不恰当的同步导致程序无法达到预期的效果。

2.2 解决方式:

  • 本场景读比写频率高,使用两个rwlock, 其中一个保护queue本身,另一个保护find_jobjob_remove等一些子线程处理queue的操作。
  • 使用variable condition处理子线程与主线程的同步问题。

3. 程序展示

[root@localhost ~]# vim 11_7.c                    
#include <stdio.h>
#include <err.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
struct job
{       
        struct job * j_next;
        struct job * j_prev;
        pthread_t j_id; 
        int num;
};
struct queue {
        struct job * q_head;
        struct job * q_tail;
        pthread_rwlock_t q_lock;//两个rwlock
        pthread_rwlock_t q_lock2;
        pthread_cond_t qp_cond;//condition variable
        pthread_mutex_t qp_mutex;
};

#define NUMNUM  3 //3个子线程
struct queue queue_list;

int queue_init(struct queue *qp)
{
        qp->q_head = NULL;
        qp->q_tail = NULL;
        if(pthread_rwlock_init(&qp->q_lock, NULL) != 0)
                return -1;
        if(pthread_rwlock_init(&qp->q_lock2, NULL) != 0)
                return -1;
        if(pthread_mutex_init(&qp->qp_mutex,NULL) != 0)
                return -1;
        if(pthread_cond_init(&qp->qp_cond,NULL) != 0)
                return -1;
        return(0);
}

//在队列头插入一个节点
void job_insert(struct queue *qp, struct job *jp)
{
        pthread_rwlock_wrlock(&qp->q_lock);                                                                                                       
        jp->j_next = qp->q_head;                                                                                                                  
        jp->j_prev = NULL;                                                                                                                        
        if (qp->q_head != NULL)                                                                                                                   
                qp->q_head->j_prev = jp;                                                                                                          
        else                                                                                                                                      
                qp->q_tail = jp;                                                                                                                  
                qp->q_head = jp;                                                                                                                  
        pthread_rwlock_unlock(&qp->q_lock);                                                                                                       
}                                                                                                                                                 
//移除指定的节点                                                                                                             
void job_remove(struct queue *qp, struct job *jp)                                                                                                 
{                                                                                                                                                 
        pthread_rwlock_wrlock(&qp->q_lock);                                                                                                       
        if (jp == qp->q_head)                                                                                                                     
        {                                                                                                                                         
                qp->q_head = jp->j_next;                                                                                                          
                if (qp->q_tail == jp)                                                                                                             
                        qp->q_tail = NULL;                                                                                                        
                else                                                                                                                              
                        jp->j_next->j_prev = jp->j_prev;                                                                                          
        } else if (jp == qp->q_tail)                                                                                                              
        {                                                                                                                                         
                qp->q_tail = jp->j_prev;                                                                                                          
                jp->j_prev->j_next = jp->j_next;                                                                                                  
        } else                                                                                                                                    
        {                                                                                                                                         
                jp->j_prev->j_next = jp->j_next;                                                                                                  
                jp->j_next->j_prev = jp->j_prev;                                                                                                  
        }                                                                                                                                         
        pthread_rwlock_unlock(&qp->q_lock);                                                                                                       
}                                                                                                                                                 

//根据给定的线程ID寻找一个对应的节点(队列最前端)                                                                                                           
struct job * job_find(struct queue *qp, pthread_t id)                                                                                             
{                                                                                                                                                 
        struct job * jp;                                                                                                                          
        pthread_rwlock_rdlock(&qp->q_lock);                                                                                                       
        for (jp = qp->q_head; jp != NULL; jp = jp->j_next)                                                                                        
                if (pthread_equal(jp->j_id, id))                                                                                                  
                        break;                                                                                                                    
        pthread_rwlock_unlock(&qp->q_lock);                                                                                                       
        return(jp);                                                                                                                               
}                                                                                                                                                 
//每个子线程处理queue的函数                                                                                                                                                  
int job_settle(struct queue *qp, pthread_t id)                                                                                                    
{                                                                                                                                                 
        struct job * jp;                                                                                                                          
        pthread_rwlock_rdlock(&qp->q_lock2);//避免了如上所述的竞态                                                                                                      
        if((jp = job_find(qp,id)) == NULL)                                                                                                        
        {                                                                                                                                         
                return -1;                                                                                                                        
        }                                                                                                                                         
        job_remove(qp,jp);                                                                                                                        
        pthread_rwlock_unlock(&qp->q_lock2);                                                                                                      
        printf("crrent thread id:%lu, and crrent job num:%d. we have done it.\n",pthread_self(),jp->num);                                         
        free(jp);                                                                                                                                 
        return 0;                                                                                                                                 

}                                                                                                                                                 

void job_modify(struct queue *qp)                                                                                                                 
{                                                                                                                                                 
        struct job * jp;                                                                                                                          
        for (jp = qp->q_head; jp->j_next != NULL; jp = jp->j_next);                                                                               
        pthread_rwlock_wrlock(&qp->q_lock2);                                                                                                      
        jp->j_id=5;//此时将最后一个job替换成不会被检索的job id,如果程序运行正常,将少打印一个job                                                  
        pthread_rwlock_unlock(&qp->q_lock2);                                                                                                      
}                                                                                                                                                 

struct job * job_create(pthread_t id,int num)                                                                                                     
{                                                                                                                                                 
        struct job * jp;                                                                                                                          
        if ((jp = malloc(sizeof(struct job))) != NULL)                                                                                            
        {                                                                                                                                         
                jp->j_id = id;                                                                                                                    
                jp->num = num;                                                                                                                    
        }                                                                                                                                         
        return(jp);                                                                                                                               
}                                                                                                                                                 

void * thr_fn(void *arg)                                                                                                                          
{                                                                                                                                                 
        char i;                                                                                                                                   
        struct job * jp;                                                                                                                          
        for(;;)                                                                                                                                   
        {                                                                                                                                         
                pthread_mutex_lock(&(&queue_list)->qp_mutex);                                                                                     
                pthread_cond_wait(&(&queue_list)->qp_cond,&(&queue_list)->qp_mutex);                                                              
                if(job_settle(&queue_list,pthread_self()) != 0)                                                                                   
                {                                                                                                                                 
                        printf("there is no  job for thread id:%lu \n",pthread_self());                                                           

                }                                                                                                                                 
                pthread_mutex_unlock(&(&queue_list)->qp_mutex);                                                                                   
        }                                                                                                                                         
}                                                                                                                                                 
//每5秒钟由主线程通知子线程处理queue                                                                                                                                                  
void sig_usr(int signo)                                                                                                                           
{                                                                                                                                                 
        pthread_cond_broadcast(&(&queue_list)->qp_cond);                                                                                          
        alarm(5);                                                                                                                                 
}                                                                                                                                                 


int main(int argc,char **argv )                                                                                                                   
{                                                                                                                                                 
        char i,j;                                                                                                                                 
        pthread_t tid[NUMNUM];                                                                                                                    
        sigset_t newmask,oldmask;                                                                                                                 
        struct job * jp;
        if(queue_init(&queue_list) == -1)
                errx(1,"queue_init error \n");                                                                                         
        //信号的屏蔽和处理                                                                                                                        
        if (signal(SIGALRM, sig_usr) == SIG_ERR)                                                                                                  
                errx(1,"signal(SIGALRM) error");                                                                                                  

        //线程的创建,3个线程(不含主线程)                                                                                                          
        for (i = 0; i < NUMNUM; i++)                                                                                                              
        {                                                                                                                                         
                if(pthread_create(tid+i, NULL, thr_fn, NULL) != 0)                                                                                
                        errx(1, "can’t create thread");                                                                                           
        }                                                                                                                                         
        //工作的创建,9个工作,每个线程3个工作                                                                                                     
        printf("initial job arrangement:\n");                                                                                                     
        for (i=0,j = 0; i < NUMNUM*3; i++)                                                                                                        
        {                                                                                                                                         
                if(j>=3)                                                                                                                          
                        j=0;                                                                                                                      
                if((jp=job_create(tid[j],i)) != NULL)                                                                                             
                {                                                                                                                                 
                        printf("job num %d for thread id %lu\n",i,tid[j++]);                                                                      
                        job_insert(&queue_list,jp);                                                                                               
                }                                                                                                                                 
                else                                                                                                                              
                        printf("error in job_create\n");                                                                                          
        }                                                                                                                                         


        //每5秒通知子线程状态的改变                                                                                                               
        alarm(5);                                                                                                                                 
        sleep(6);                                                                                                                                 
        //在6秒修改最后一个成员的信息                                                                                                             
        job_modify(&queue_list);                                                                                                                  
        for(;;)                                                                                                                                   
        {                                                                                                                                         
        }                                                                                                                                         
} 

4. 结果分析

[root@localhost ~]# ./11_7                        
initial job arrangement:
job num 0 for thread id 140584030320384
job num 1 for thread id 140584021927680
job num 2 for thread id 140584013534976
job num 3 for thread id 140584030320384
job num 4 for thread id 140584021927680
job num 5 for thread id 140584013534976
job num 6 for thread id 140584030320384
job num 7 for thread id 140584021927680
job num 8 for thread id 140584013534976
crrent thread id:140584030320384, and crrent job num:6. we have done it.
crrent thread id:140584021927680, and crrent job num:7. we have done it.
crrent thread id:140584013534976, and crrent job num:8. we have done it.
crrent thread id:140584030320384, and crrent job num:3. we have done it.
crrent thread id:140584021927680, and crrent job num:4. we have done it.
crrent thread id:140584013534976, and crrent job num:5. we have done it.
there is no  job for thread id:140584030320384 
crrent thread id:140584021927680, and crrent job num:1. we have done it.
crrent thread id:140584013534976, and crrent job num:2. we have done it.
there is no  job for thread id:140584030320384 
there is no  job for thread id:140584013534976 
there is no  job for thread id:140584021927680 
there is no  job for thread id:140584030320384 
there is no  job for thread id:140584021927680 
there is no  job for thread id:140584013534976 
there is no  job for thread id:140584030320384 
there is no  job for thread id:140584021927680 
there is no  job for thread id:140584013534976 
there is no  job for thread id:140584030320384 
there is no  job for thread id:140584021927680 
there is no  job for thread id:140584013534976 
^C

  可以看到,结果和我们预期要实现的一样:9个job,却只打印了8个,其中0job被主线程在运行一半的时候修改了Thread ID而不隶属于任何一个线程。线程 140584030320384本来应该处理0job,结果却提示自己已经没有任务了。
  本题目经过笔者自己设计修改,可能有些地方代码写的并不合适,但是本代码只是学习过程中的小练手。为了迎接未来更复杂,更棘手的场景,这是笔者必经之路。如果对以上论述有质疑的读者,请及时指正。

版权声明:本文为博主原创文章,未经博主允许不得转载。

java 多线程等待与唤醒机制

java 并发编程网站 :http://ifeve.com/java-7-concurrency-cookbook/ 一: 1:JVM线程状态 NEW, RUNNABLE, BLOC...
  • baiducheng
  • baiducheng
  • 2017年12月25日 16:08
  • 60

java 多线程 future 基本原理

/** * Date:2016年9月7日下午7:56:03 * Copyright (c) 2016, www.bwbroad.com All Rights Reserved. * */ p...
  • xuejianxinokok
  • xuejianxinokok
  • 2016年09月12日 22:23
  • 514

GCD多线程之dispatch queue

GCD多线程   GCD之dispatch queue iOS中多线程编程工具主要有: •   NSThread •  NSOperation •  GCD 这三种方法都简单易用,各有千...
  • drm521
  • drm521
  • 2014年07月09日 21:55
  • 277

多线程之使用信号量

引言信号量作为GCD的一部分,常用于多线程或任务间协作,当一个任务的执行过程中需要依赖另一个任务时即可使用信号量。实现原理信号量通过信号计数来实现。其使用即计数过程可分为三个部分:创建信号量、等待信号...
  • l964968324
  • l964968324
  • 2015年09月10日 18:56
  • 438

Android Priority Job Queue (Job Manager):多重不同Job并发执行并在前台获得返回结果(四)

Android Priority Job Queue (Job Manager):多重不同Job并发执行并在前台获得返回结果(四)在Android Priority Job Queue (Job ...
  • zhangphil
  • zhangphil
  • 2016年11月02日 11:22
  • 1323

代码笔记 | 多线程使用queue模块同步访问共享数据

import threading,queue,time numproducer=4 nummessages=4 numconsumer=2 dataQueue=queue.Queue() saf...
  • CodePudge
  • CodePudge
  • 2016年09月01日 15:28
  • 210

java多线线程用法总结

文章目录: 1、线程的定义 2、线程的创建于启动 3、线程的生命周期 4、线程的安全问题...
  • huanghi11
  • huanghi11
  • 2015年10月24日 19:01
  • 741

JAVA基础学习(十二)--多线程一线程之间的通信

线程之间的通信
  • ko0491
  • ko0491
  • 2015年09月18日 16:10
  • 206

(六)java多线程之ReadWriteLock

本人邮箱: kco1989@qq.com 欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kco github: https://github.com/...
  • tianshi_kco
  • tianshi_kco
  • 2016年10月29日 15:46
  • 400

oracle job queue/oracle 作业队列

一、作業的概念    作業是一組PL/SQL代碼,用於完成特定的功能。它由作業調度囂調度執行,可以將它比較我們日常工作中的工作安排,它在將來的某個時間點自動執行,或在每間隔一段時間後自動重復執行。 二...
  • truexf
  • truexf
  • 2007年03月21日 20:33
  • 3873
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:多线程之Job queue实验(六)
举报原因:
原因补充:

(最多只允许输入30个字)