PDA

View Full Version : سوال: مشکل ارسال Reference اشیاء بین دو thread



m2011kh
چهارشنبه 26 آبان 1395, 19:48 عصر
سلام و خسته نباشید خدمت دوستان عزیز.


سوال بنده از این قرار هست. در حالت عادی میشه به عنوان پارامتر یک یا آرایه ای از رفرنس های اشیاء رو از شیئی به شیئ دیگر فرستاد. حالا مسئله اینجاست:

تا اونجایی که بنده متوجه شدم ارجاع رفرنسی از شیئی بین دو کلاس به عنوان پارامتری از یک تابع در حالتی که بین دو نخ مختلف باشند ممکن نیست. الان سوال بنده اینه که وقتی که چند نخ داریم، این ارجاع رفرنس ها بین توابع و کلاس هارو در کل چطور باید کنترل و مدیریت کرد؟

دوستان اگه مقاله ای یا پاسخی در این مورد دارید، ممنون میشم که پست کنید.

موفق و سربلند باشید.

kamiloted
یک شنبه 30 آبان 1395, 00:51 صبح
سلام و خسته نباشد.
شرمنده كه اسپم ميدم ولي واقعا يعني كسي جوابي براي اين سوال نداشت؟

امیدوارم به دردت بخوره.


typedef struct
{
double *a;
double *b;
double sum;
int veclen;
} DOTDATA;

/* Define globally accessible variables and a mutex */

#define NUMTHRDS 4
#define VECLEN 100

DOTDATA dotstr; //GLOBAL DATA which is going to be accessed by different threads

pthread_t callThd[NUMTHRDS];
pthread_mutex_t mutexsum;

void *dotprod(void *arg)
{

/* Define and use local variables for convenience */

int i, start, end, len ;
long offset;
double mysum, *x, *y;
offset = (long)arg;

len = dotstr.veclen;
start = offset*len;
end = start + len;
x = dotstr.a;
y = dotstr.b;

/*
Perform the dot product and assign result
to the appropriate variable in the structure.
*/

mysum = 0;
for (i=start; i<end ; i++)
{
mysum += (x[i] * y[i]);
}

/*
Lock a mutex prior to updating the value in the shared
structure, and unlock it upon updating.
*/
pthread_mutex_lock (&mutexsum);
dotstr.sum += mysum;
pthread_mutex_unlock (&mutexsum);

pthread_exit((void*) 0);
}

int main (int argc, char *argv[])
{
long i;
double *a, *b;
void *status;

/* Assign storage and initialize values */
a = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));
b = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));

for (i=0; i<VECLEN*NUMTHRDS; i++)
{
a[i]=1.0;
b[i]=a[i];
}

dotstr.veclen = VECLEN;
dotstr.a = a;
dotstr.b = b;
dotstr.sum=0;

pthread_mutex_init(&mutexsum, NULL);

for(i=0; i<NUMTHRDS; i++)
{
/*
Each thread works on a different set of data.
The offset is specified by 'i'. The size of
the data for each thread is indicated by VECLEN.
*/
pthread_create(&callThd[i], NULL, dotprod, (void *)i);
}

/* Wait on the other threads */
for(i=0; i<NUMTHRDS; i++)
{
pthread_join(callThd[i], &status);
}

printf ("Sum = %f \n", dotstr.sum);
free (a);
free (b);
pthread_mutex_destroy(&mutexsum);
pthread_exit(NULL);//No need of pthread_join() if pthread_exit() used.
}







class Program
{
static void Main()
{
Thread FirstThread = new Thread(new ThreadStart(Fun1));
Thread SecondThread = new Thread(new ThreadStart(Fun2));
FirstThread.Start();
SecondThread.Start();


}
public static void Fun1()
{
for (int i = 1; i <= 1000; i++)
{
Console.WriteLine("Fun1 writes:{0}", i);
}
}
public static void Fun2()
{
for (int i = 1000; i >= 6; i--)
{
Console.WriteLine("Fun2 writes:{0}", i);
}
}

}

m2011kh
یک شنبه 30 آبان 1395, 01:33 صبح
امیدوارم به دردت بخوره.


typedef struct
{
double *a;
double *b;
double sum;
int veclen;
} DOTDATA;

/* Define globally accessible variables and a mutex */

#define NUMTHRDS 4
#define VECLEN 100

DOTDATA dotstr; //GLOBAL DATA which is going to be accessed by different threads

pthread_t callThd[NUMTHRDS];
pthread_mutex_t mutexsum;

void *dotprod(void *arg)
{

/* Define and use local variables for convenience */

int i, start, end, len ;
long offset;
double mysum, *x, *y;
offset = (long)arg;

len = dotstr.veclen;
start = offset*len;
end = start + len;
x = dotstr.a;
y = dotstr.b;

/*
Perform the dot product and assign result
to the appropriate variable in the structure.
*/

mysum = 0;
for (i=start; i<end ; i++)
{
mysum += (x[i] * y[i]);
}

/*
Lock a mutex prior to updating the value in the shared
structure, and unlock it upon updating.
*/
pthread_mutex_lock (&mutexsum);
dotstr.sum += mysum;
pthread_mutex_unlock (&mutexsum);

pthread_exit((void*) 0);
}

int main (int argc, char *argv[])
{
long i;
double *a, *b;
void *status;

/* Assign storage and initialize values */
a = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));
b = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));

for (i=0; i<VECLEN*NUMTHRDS; i++)
{
a[i]=1.0;
b[i]=a[i];
}

dotstr.veclen = VECLEN;
dotstr.a = a;
dotstr.b = b;
dotstr.sum=0;

pthread_mutex_init(&mutexsum, NULL);

for(i=0; i<NUMTHRDS; i++)
{
/*
Each thread works on a different set of data.
The offset is specified by 'i'. The size of
the data for each thread is indicated by VECLEN.
*/
pthread_create(&callThd[i], NULL, dotprod, (void *)i);
}

/* Wait on the other threads */
for(i=0; i<NUMTHRDS; i++)
{
pthread_join(callThd[i], &status);
}

printf ("Sum = %f \n", dotstr.sum);
free (a);
free (b);
pthread_mutex_destroy(&mutexsum);
pthread_exit(NULL);//No need of pthread_join() if pthread_exit() used.
}







class Program
{
static void Main()
{
Thread FirstThread = new Thread(new ThreadStart(Fun1));
Thread SecondThread = new Thread(new ThreadStart(Fun2));
FirstThread.Start();
SecondThread.Start();


}
public static void Fun1()
{
for (int i = 1; i <= 1000; i++)
{
Console.WriteLine("Fun1 writes:{0}", i);
}
}
public static void Fun2()
{
for (int i = 1000; i >= 6; i--)
{
Console.WriteLine("Fun2 writes:{0}", i);
}
}

}



سلام دوست عزیز و ممنونم از پاسختون.

کد اولی کد C++ هست و متأسفانه به کار من در کل نمیاد.

و کد دومی حس میکنم که بنده سوالم رو کمی بد مطرح کرده بودم. الان سعی میکنم که به روش بهتری سوالم رو دوباره تشریح کنم.

این مشکل زمانی اتفاق افتاد که من یک پروژه ای داشتم که باید چهار Picturebox رو همزان با سرعت های رندوم به سمتی حرکت میدادم. این پروسه از چند لایه رد میشه.اول رفرنسی از هر PictureBox به یه کلاس دیگه فرستاده میشه و اونجا سرعت و یک معیار تغییر سرعت تصادفی تعیین میشه و بعد این تابع چهار تا نخ به اضای هر PictureBox میسازه و استارت میکنه. ارور زمانی اتفاق می افته که تابعٍ آخرین کلاسی که رفرنس PictureBoxهارو دریافت میکنه میخواد PicuteBox رو به وسیله ی رفرنسی که دریافت کرده حرکت بده. اینجاست که کامپایلر ارور میده که PictureBox ها کلاسی از یک نخ دیگه هستن و این نخ نمیتونه به اونها دسترسی داشته باشه.

سوال من در واقع حل این مشکل بود.

ولی باز هم ممنون از پاسختون.

موفقو سربلند باشید.

kamiloted
یک شنبه 30 آبان 1395, 01:45 صبح
سلام دوست عزیز و ممنونم از پاسختون.

کد اولی کد C++‎ هست و متأسفانه به کار من در کل نمیاد.

و کد دومی حس میکنم که بنده سوالم رو کمی بد مطرح کرده بودم. الان سعی میکنم که به روش بهتری سوالم رو دوباره تشریح کنم.

این مشکل زمانی اتفاق افتاد که من یک پروژه ای داشتم که باید چهار Picturebox رو همزان با سرعت های رندوم به سمتی حرکت میدادم. این پروسه از چند لایه رد میشه.اول رفرنسی از هر PictureBox به یه کلاس دیگه فرستاده میشه و اونجا سرعت و یک معیار تغییر سرعت تصادفی تعیین میشه و بعد این تابع چهار تا نخ به اضای هر PictureBox میسازه و استارت میکنه. ارور زمانی اتفاق می افته که تابعٍ آخرین کلاسی که رفرنس PictureBoxهارو دریافت میکنه میخواد PicuteBox رو به وسیله ی رفرنسی که دریافت کرده حرکت بده. اینجاست که کامپایلر ارور میده که PictureBox ها کلاسی از یک نخ دیگه هستن و این نخ نمیتونه به اونها دسترسی داشته باشه.

سوال من در واقع حل این مشکل بود.

ولی باز هم ممنون از پاسختون.

موفقو سربلند باشید.

دریافت شد.
کد اول برای سی بود.
یه نمونه براتون مینویسم تا فردا براتون میزارم.موفق باشید.

m2011kh
شنبه 13 آذر 1395, 17:02 عصر
سلام و خسته نباشید دوستان.

دوستان که این تایپیک رو بی جواب گذاشتن ولی چون خودم پاسخ رو پیدا کردم اینجا میزارم که اگه بعدا کسی به این مشکل برخورد بتونه جواب سوال رو اینجا پیدا کنه.

دو متد از دو کلاس متفاوت هستن در حالتی که در نخ های مختلفی باشند نمیتونن به خصوصیات و کنترل های همدیگه دسترسی داشته باشن. یه مثال کوچیک:

فرم 1 توی نخ0 در حال اجرا هست و فرم یک یک تکست باکس داره.

کلاس 1 توی نخ1 در حال اجرا هست و میخواد به تکست باکس فرم 1 دسترسی داشته باشه. این در حالت عادی و یک خطای استثناء تولید میکنه.


راه حل:

در واقع باید دستوری که در شیء که در نخ دیگری هست رو به خودش بدیم که برامون انجام بده در نخ خودش. در مثال بالا باید کلاس 1 دستور رو به نخ0 منتقل کنه تا اونجا اجرا بشه.

و این برای کنترل ها بوسیله تابع BeginInvoke قابل انجام هست که البته به عنوان پارامتر به یک Delegate از کدی که به نخ مقصد میخواید بفرستید نیاز داره. از این تابع برای بروز رسانی کنترل های فرم از نخ های دیگر استفاده میشه ولی در کل به ابزار dispatcher گفته میشه که به غیر از این کاربرد، کاربرد های زیادی داره در مورد برنامه نویسی چند نخی.

یه مثال کوچیگی که نوشتم برای درک بهتر:

کد فرم:
namespace Test_Dispetcher
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
testerKlasse tst = new testerKlasse();
Thread testthread = new Thread(delegate() { tst.MMD(textBox1); });
testthread.Start();
}
}
}




کد کلاسی که تابعی در اون به عنوان نخ جدید اجرا میشه:


namespace Test_Dispetcher
{
class testerKlasse
{
public delegate void del();
public void MMD(TextBox testTextBox)
{
TextBox tstTextBox = testTextBox;
del meindel = new del(delegate() {tstTextBox.Text = "SSS";});


tstTextBox.BeginInvoke(meindel);
}
}
}


امیدوارم که برای دوستان مفید واقع بشه.


موفق و سربلند باشید.
M.M.D