الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

عندي مشكله في برنامج Producer - Consumer

بدأه Elsayed Abd Elhalim في 26 فبراير 2009 · 15 رد · 1,418 مشاهدة · في JavaSE
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم ورحمة الله وبركاته

البرنامج هو عندي عدد من producer وعدد من consumer وعندي buffer الوسيط بين producer و consumer

كل واحد من producer ينتج منتج يضعة في buffer إذا كان فيه مكان فاضي و إلا ينتظر

وكل واحد من consumer يأخذ منتج من ال buffer إذا كان فيه منتجات و إلا ينتظر

أنا عملت البرنامج ويعمل بشكل سليم في حالة عندي producer واحد و consumer واحد

ولكن إذا زاد عدد أي من producer او consumer يعطي نتائج غير متوقعة

أرجو من أساتذتي الخبراء يفيدوني في حل هذه المشكله

package producer_consumer;

/**
 *
 * @author Elsayed
 */
public class CircularQueue {

	private String[] queue;
	private int size;
	private int count;
	private int front;
	private int rear;

	public CircularQueue(int size) {
		this.size = size;
		queue = new String[size];
		count = 0;
		front = 0;
		rear = 0;
	}

	private boolean isEmpty(){
		return (count == 0);
	}
	private boolean isFull(){
		return (count == size);
	}

	synchronized public void get(String consumed) {
		if(isEmpty()){
			try{
				wait();
			}
			catch(Exception e){
				System.err.println("Thread Interrupted");
			}
		}		
		front %= size;
		count--;
		System.out.println(consumed + queue[front++] + " <<-- ( " + 
				count + " )" );
		notify();
	}

	synchronized public void put(String item) {
		if(isFull()){
			try{
				wait();
			}
			catch(Exception e){
				System.err.println("Thread Interrupted");
			}
		}
		count++;
		System.out.println(item + "-->> ( " + count + " )" );
		rear %= size;
		queue[rear++] = item;		
		notify();
	}

}

package producer_consumer;

/**
 *
 * @author Elsayed
 */
public class Producer extends Thread{
	private CircularQueue queue;
	private String producerName;
	private int item = 0;

	public Producer(CircularQueue queue, String pName) {
		this.queue = queue;
		producerName = pName;		
	}

	public void run() {
		while(true)			
			queue.put(producerName + " : " + "Item ( " + (++item) + " )" );
	}


}

package producer_consumer;

/**
 *
 * @author Elsayed
 */
public class Consumer extends Thread{
	private CircularQueue queue;
	private String consumerName;

	public Consumer(CircularQueue queue, String cName) {
		this.queue = queue;
		consumerName = cName;		
	}

	public void run() {
		while(true)
			queue.get(consumerName + " consumes ");


	}

}

package producer_consumer;

/**
 *
 * @author Elsayed
 */
public class Main {

	static final int NUM_OF_PRODUCERS = 1;
	static final int NUM_OF_CONSUMERS = 1;
	static final int BUFFER_SIZE = 3;

	/**
	 * @param args the command line arguments
	 */
	public static void main(String[] args) {

		Producer[] producer = new Producer[NUM_OF_PRODUCERS];
		Consumer[] consumer = new Consumer[NUM_OF_CONSUMERS];
		CircularQueue buffer = new CircularQueue(BUFFER_SIZE);

		for(int i = 0; i < producer.length; i++){
			producer = new Producer(buffer, "Producer # [" + ( i+1 ) + "]");
			producer.start();
		}

		for(int i = 0; i < consumer.length; i++){
			consumer = new Consumer(buffer, "consumer # [" + ( i+1 ) + "]");
			consumer.start();
		}

	}

}
#2

السلام عليكم

ماذا لو استعملت notifyall بدلا من notify

#3

وعليكم السلام ورحمة الله وبركاته

أشكرك أخي على ردك

إذا استعملت notifyall بدلا من notify تعطي نفس النتائج

#4

السلام عليكم

لماذا لم تقم بتعريف الدالة notify ، او هي معرفة مسبقاً بسبب وجود الكلمة synchronized ؟

جربت البرنامج ب 2 cons و 2 prod والنتائج ظهرت فيها اخطاء ، مثلا ارقام بالسالب:

Producer # [1]:Item (1)-->> ( 1 )
consumer # [1] consumes Producer # [1]:Item (1) <<-- ( 0 )
Producer # [2]:Item (1)-->> ( 1 )
Producer # [1]:Item (2)-->> ( 2 )
Producer # [2]:Item (2)-->> ( 3 )
consumer # [2] consumes Producer # [2]:Item (1) <<-- ( 2 )
consumer # [1] consumes Producer # [1]:Item (2) <<-- ( 1 )
consumer # [2] consumes Producer # [2]:Item (2) <<-- ( 0 )
Producer # [2]:Item (3)-->> ( 1 )
Producer # [1]:Item (3)-->> ( 2 )
Producer # [2]:Item (4)-->> ( 3 )
consumer # [2] consumes Producer # [2]:Item (3) <<-- ( 2 )
consumer # [1] consumes Producer # [1]:Item (3) <<-- ( 1 )
consumer # [1] consumes Producer # [2]:Item (4) <<-- ( 0 )
Producer # [2]:Item (5)-->> ( 1 )
Producer # [2]:Item (6)-->> ( 2 )
Producer # [2]:Item (7)-->> ( 3 )
consumer # [2] consumes Producer # [2]:Item (5) <<-- ( 2 )
consumer # [2] consumes Producer # [2]:Item (6) <<-- ( 1 )
consumer # [2] consumes Producer # [2]:Item (7) <<-- ( 0 )
consumer # [1] consumes Producer # [2]:Item (5) <<-- ( -1 )
consumer # [2] consumes Producer # [2]:Item (6) <<-- ( -2 )
Producer # [1]:Item (4)-->> ( -1 )
Producer # [2]:Item (8)-->> ( 0 )
Producer # [1]:Item (5)-->> ( 1 )

تم تعديل هذه المشاركة بواسطة مجلـد جديـد في 28 فبراير 2009 في 00:34

#5

معذرة ، لم استطع حذف الرد

تم تعديل هذه المشاركة بواسطة مجلـد جديـد في 28 فبراير 2009 في 00:33

#6

السلام عليكــم ورحمـة الله وبركاتــة ،

بعد تأملي و تجريبي للكود اتضح لي مايلي:

1- المتود get سمح ل a consumer باستهلاك ما هو موجود بالbufferو الذي أنتج بواسطة a producer

ولهذا تكون كمايلي:

synchronized public String get() {
        if(isEmpty()){
            try{
                wait();
            }
            catch(Exception e){
                System.err.println("Thread Interrupted");
            }
        }        
        front %= size;
        count--;
     /*   System.out.println(consumed + queue[front++] + " <<-- ( " + 
                count + " )" );*/
        notify();
return queue[front++];
    }

2- ولكن يظل هناك خطأ بالنسبة لمؤشرات الاستهلاك والإنتاج

ألاحظ بأنه لايتم بالإنتاج في queue[0]وكذلك الاستهلاك منه

فيتم الزيادة ب 1 قبل استخدام الخانة ذات المؤشر 0

مثلا هاهو الكود للمتود put:

synchronized public void put(String item) {
        if(isFull()){
            try{
                wait();
            }
            catch(Exception e){
                System.err.println("Thread Interrupted");
            }
        }
         queue[rear] = item;
        count++;
        rear = (rear+1) % size;

        System.out.println(item + "-->> ( " + count + " )" );
        notify();
    }

في انتظار تعقيباتكم

#7

اخي asminf ، اناا اعشق data structures بشكل غير معقول ، لذلك الموضوع هذا دائما ادخله واحاول فيه :D

كتبت كود لاستبدال Queue بـ Stack لكن ظهرت لي مشاكل خلال run time متعلقة بالمصفوفة و indexing

public class Stack {

	private String[] stack;
	private int size;
	private int count;
	private int top;

	public Stack(int size) {
		this.size = size;
		stack = new String[size];
		//count = 0;
		top = -1;
	}

	private boolean isEmpty(){
		return (top == -1);
	}
	private boolean isFull(){
		return ((top+1) == size);
	}

	synchronized public void pop(String consumed) 
	{
		if(isEmpty()){
			try{
				wait();
			}
			catch(Exception e){
				System.err.println("Thread Interrupted");
			}
		}		
		//top--;

		try
		//System.out.println(consumed + stack[top] + " <<-- ( " +		count + " )" );
		{
			System.out.println(consumed +": consumes "+stack[top]+" poped from slot#:"+top);
		}
		catch(Exception e)
		{
			System.out.println(e);
		}

		//count--;
		top--;
		notify();
	}

	synchronized public void push(String item) {
		if(isFull()){
			try{
				wait();
			}
			catch(Exception e){
				System.err.println("Thread Interrupted");
			}
		}

		//System.out.println(item + "-->> ( " + count + " )" );
		//rear %= size;
		//count++;
		top++;
		try
		{
		stack[top] = item;		
		}
		catch(Exception e)
		{
			System.out.println(e);
		}

		System.out.println( item+" pushed into slot#:"+top);

		notify();
	}

}
#8

asminf

الا تعتقد ان الخطأ يكمن في استخدام wait() و notify() بطريقة خاطئة؟

#9

أخي مجلد جديد ولم خطر في بالك فقط هذ التبديل ألا تعلم بأن الجافا stack oriented أي كل تنفيذ لبرنامج جافا يكون في stack created on jvm ربما أخلطت على الjvm كل الأمور :D

أكيد أنا أمزح لم أدقق في الكود سأحاول أن أتأمله وأجربه ربما سأجد السبب!!!

أعتقد لحد كبير بأنها الstack?!لأنه يو جد كلاس stack في الجي دي كا جافا....

#10

المشكلة تكمن في السيناريو التالي

فلان من المستهلكين محجوز على أساس أنه منحل ويحاول لطش منتجات بدون رصيد

أووووووه

لقد تبين أن هناك منتجات جديدة لكن الشرطة لم تعلم بالأمر

المشكلة أنه ليس الطالب الوحيد للمنتج

يظهر أن المثال لم يكن واضحاً

لكن الحل يكمن في منع من يدخل إلى جملة if من الخروج منها

كما يهيألي أنه لو كان هناك منتج ومستهلك يعملون في نفس التزامن فستحصل مشكلة في المتغير count

وذلك لأن كليهما يقوم بالتعديل عليه

(هذه المشكلة لم تحصل معي عندما جربت الشيفرة لكني أظن أنها ممكنة)

لهذا أرجح استخدام آلية التزامن الخاصة بحماية الشيفرة في أكثر من دالة والمسماة Semaphore

أو استخدام الكلمة المحجوزة volatile

أي أسئلة أنا جاهز للإجابة

تحياتي

حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

#11

الله ينور عليك اخوي علاء ، عرفت الخطأ من السطر هذا:

اقتباس
لكن الحل يكمن في منع من يدخل إلى جملة if من الخروج منها

الكود الصحيح بعد التعديل:

ملف Stack.java (ويمكن استخدام ملف Queue.java لكن لابد من التعديل عليه في جمل if في دالة put&get ):

public class Stack 
{

	private String[] stack;
	private int size;
	private int top;


	public Stack(int size) 
	{
		this.size = size;
		stack = new String[size];
		top = -1;

	}

	private boolean isEmpty()
	{
		System.out.println( top+"=="+"-1" );
		return (top == -1);
	}

	private boolean isFull()
	{
		System.out.println( (top+1) +"=="+size );
		return ( (top+1) == size );
	}

	synchronized public void push(String item) 
	{
		if( isFull() )
		{
			try
			{
				wait();
			}
			catch(Exception e)
			{
				System.err.println("Thread Interrupted");
			}
		}
		else
		{


			top++;
			try
			{
				stack[top] = item;
			}
			catch(Exception e)
			{
				System.out.println("push():"+item+"\n"+e.toString());
			}

			System.out.println( "\""+item+"\" pushed into slot#: "+top);


			notify();
		}

	}

	synchronized public void pop(String consumed) 
	{
		if( isEmpty() )
		{
			try
			{
				wait();
			}
			catch(Exception e)
			{
				System.err.println("Thread Interrupted");
			}
		}
		else
		{
			try
			{
				System.out.println(consumed+":\""+stack[top]+"\" poped from slot#: "+top);
			}
			catch(Exception e)
			{
				System.out.println("pop():"+consumed+"\n"+e.toString());
			}

			top--;



			notify();
		}




	}
}

ملف Producer و Consumer و Main :

public class Producer extends Thread
{
	private Stack stack;
	private String producerName;
	private int item = 0;


	public Producer(Stack stack, String pName) 
	{
		this.stack = stack;
		producerName = pName;		
	}

	public void run() 
	{
		while(true)
		{
			item++;
			stack.push("prod["+producerName+"]("+item+")" );
		}

	}


}

public class Consumer extends Thread
{
	private Stack stack;
	private String consumerName;

	public Consumer(Stack stack, String cName) 
	{
		this.stack = stack;
		consumerName = cName;		
	}

	public void run() {
		while(true)
		{

				stack.pop("cons["+consumerName+"]");
		}



	}

}

public class Main {

	static final int NUM_OF_PRODUCERS = 2;
	static final int NUM_OF_CONSUMERS = 2;
	static final int BUFFER_SIZE = 3;

	/**
	 * @param args the command line arguments
	 */
	public static void main(String[] args) {

		Producer[] producer = new Producer[NUM_OF_PRODUCERS];
		Consumer[] consumer = new Consumer[NUM_OF_CONSUMERS];
		Stack buffer = new Stack(BUFFER_SIZE);

		for(int i = 0; i < producer.length; i++){
			producer = new Producer(buffer, i+"");
			producer.start();
		}

		for(int i = 0; i < consumer.length; i++){
			consumer = new Consumer(buffer, i+"" );
			consumer.start();
		}

	}

}

الرجاء اخباري عن اي مشكلة تظهر في البرنامج ، وبعد قليل سوف اقوم بتعديل ملف Queue.java وارفاقه.

وللتوضيح ، المشكلة انحلت بعد اضافة else في دالة الاضافة والازاله.

هههههههههههههههههه

صاحب الموضوع وينه :D ؟

تم تعديل هذه المشاركة بواسطة مجلـد جديـد في 2 مارس 2009 في 18:20

#12

صحيح أخ مجلد جديد

ممكن أن تضيف جملة return أيضاً

وستقوم بنفس العمل الذي قامت به else بدون أي فارق

تحياتي

حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

#13

السلام عليكم

أرى بأنه تم إلغاء تام للكاونت ؟!!! لم أجربه بعد..

ماذا لو تم استخدام while بدل If.. else

بالنسبة للمتود isFull, isEmpty

أضن يجب التصريح بهم مع synchronized لحالة الوصول الخارجي للمتودس"أي ليس من نفس الكلاس كما هو مبرمج"

#14

فعلاً كلام صحيح بالنسبة للدوال isEmpty و isFull

لكن بالنسبة للمتغير count مازال يعمل لكن سيحدث في المنطق لو استخدمنا if else

وأظن أن while هي الأفضل

على كل حال الخطأ المنطقي هنا هو أن المستهلك أراد أن يستهلك ورجع بدون ذلك

لو اعتبرنا أن المستخدم يريد أن يستهلك ولم يجد شيء يستهلكه فرجع فسيكون المنطق صحيح

على كل الحالات لا خطأ منطقي حقيقي لا زال كل شيء يعمل كما هو

في كل الحالات

تحياتي

حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

#15

السلام عليكــم ورحمـة الله وبركاتــة ،،

لقد قمت بتعديلات على الكود وأضنه صحيح من أجل أكثر من مستهلك ومنتج واحد

لأجل الbuffer:

public class CircularQueue {

private String[] queue;
private int size;
private int count;
private int front;
private int rear;

public CircularQueue(int size) {
this.size = size;
queue = new String[size];
count = 0;
front = 0;
rear = 0;
}

private synchronized boolean isEmpty(){
return (count == 0);
}
private synchronized boolean isFull(){
return (count == size);
}

synchronized public String get (String consumerName){
while (isEmpty()){
try{
wait();
}
catch(Exception e){
System.err.println("Thread Interrupted");
}
} 
String msg=queue[front];
front = (front+1) % size;
count--; 
System.out.println(consumerName + msg + " <<-- " +"count= "+count);
notify();
return msg;
}

synchronized public void put(String item,int Nitem) {
while (isFull()){
try{
wait();
}
catch(Exception e){
System.err.println("Thread Interrupted");
}
}
queue[rear++] = item;
rear =(rear+1)% size;
count++; 
System.out.println(item + " : " + "Item ( " + (Nitem) + " )" + "-->> "+"count="+count );
notify();
}

}

كلاس المنتجين:

public class Producer extends Thread{
private CircularQueue queue;
private String producerName;
private int item = 0;

public Producer(CircularQueue queue, String pName) {
this.queue = queue;
producerName = pName; 
}

public void run() {

while(true){
queue.put(producerName, item );
item++;

}
}


}

كلاس المستهلكين:

public class Consumer extends Thread{
private CircularQueue queue;
private String consumerName;

public Consumer(CircularQueue queue, String cName) {
this.queue = queue;
consumerName = cName; 
}

public void run() {

while(true){

String msg = queue.get(consumerName + " consumes ");}

}

}

وهاهو الكلاس ماين:

public class Main {

static final int NUM_OF_PRODUCERS = 3;
static final int NUM_OF_CONSUMERS = 3;
static final int BUFFER_SIZE = 3;

/**
* @param args the command line arguments
*/
public static void main(String[] args) {

Producer[] producer = new Producer[NUM_OF_PRODUCERS];
Consumer[] consumer = new Consumer[NUM_OF_CONSUMERS];
CircularQueue buffer = new CircularQueue(BUFFER_SIZE);


for(int i = 0; i < producer.length; i++){
producer = new Producer(buffer, "Producer # [" + ( i+1 ) + "]");
consumer = new Consumer(buffer, "consumer # [" + ( i+1 ) + "]");

}
for(int i = 0; i < producer.length; i++){
producer.start();
consumer.start();
}

}
}

وأضن الكاونت يغير فيه بصفة منطقية وصحيحة.

أي تصويبات على الكود ....

تم تعديل هذه المشاركة بواسطة asminf في 5 مارس 2009 في 00:10

#16

لو أمكن أن توضحي الخطأ الذي تواجيهيه في if else

تحياتي

حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

مواضيع مشابهة