مشروع شركتي الجديدة ، يريدون تشغيل الكود 32 بت ، خادم الترجمة هو CentOS 5.0 مع GCC 4.1.1 ، كان هذا الكابوس.
هناك الكثير من الوظائف التي تستخدم في المشروع مثل __sync_fetch_and_add
أعطيت في دول مجلس التعاون الخليجي 4.1.2 وما بعدها.
قيل لي لا يمكنني ترقية إصدار GCC ، لذلك يجب أن أقوم بعمل حل آخر بعد Googling لعدة ساعات.
عندما كتبت عرضًا تجريبيًا للاختبار ، تلقيت للتو إجابة خاطئة ، وتريد ضربة الشفرة استبدال الوظيفة __sync_fetch_and_add
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
static int count = 0;
int compare_and_swap(int* reg, int oldval, int newval)
{
register char result;
#ifdef __i386__
__asm__ volatile ("lock; cmpxchgl %3, %0; setz %1"
: "=m"(*reg), "=q" (result)
: "m" (*reg), "r" (newval), "a" (oldval)
: "memory");
return result;
#elif defined(__x86_64__)
__asm__ volatile ("lock; cmpxchgq %3, %0; setz %1"
: "=m"(*reg), "=q" (result)
: "m" (*reg), "r" (newval), "a" (oldval)
: "memory");
return result;
#else
#error:architecture not supported and gcc too old
#endif
}
void *test_func(void *arg)
{
int i = 0;
for(i = 0; i < 2000; ++i) {
compare_and_swap((int *)&count, count, count + 1);
}
return NULL;
}
int main(int argc, const char *argv[])
{
pthread_t id[10];
int i = 0;
for(i = 0; i < 10; ++i){
pthread_create(&id[i], NULL, test_func, NULL);
}
for(i = 0; i < 10; ++i) {
pthread_join(id[i], NULL);
}
//10*2000=20000
printf("%d\n", count);
return 0;
}
عندما حصلت على النتيجة الخاطئة:
[[email protected] workspace]# ./asm
17123
[[email protected] workspace]# ./asm
14670
[[email protected] workspace]# ./asm
14604
[[email protected] workspace]# ./asm
13837
[[email protected] workspace]# ./asm
14043
[[email protected] workspace]# ./asm
16160
[[email protected] workspace]# ./asm
15271
[[email protected] workspace]# ./asm
15280
[[email protected] workspace]# ./asm
15465
[[email protected] workspace]# ./asm
16673
أدرك في هذا الخط
compare_and_swap((int *)&count, count, count + 1);
count + 1
كان خطأ!
ثم كيف يمكنني تنفيذ نفس الوظيفة __sync_fetch_and_add
. ال compare_and_swap
تعمل الدالة عندما تكون المعلمة الثالثة ثابتة.
على فكرة، compare_and_swap
الوظيفة هل هذا صحيح؟ لقد بحثت في Google من أجل ذلك ، وليس على دراية بالتجمع.
شعرت باليأس مع هذا السؤال.
……………………………………………………………………………………………………………………………………… …………………………………………………………………………………
بعد رؤية الإجابة أدناه ، أستخدم حينها وحصلت على الإجابة الصحيحة ، ولكن يبدو أن الأمر أكثر إرباكًا. هنا هو الرمز:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
static unsigned long count = 0;
int sync_add_and_fetch(int* reg, int oldval, int incre)
{
register char result;
#ifdef __i386__
__asm__ volatile ("lock; cmpxchgl %3, %0; setz %1" : "=m"(*reg), "=q" (result) : "m" (*reg), "r" (oldval + incre), "a" (oldval) : "memory");
return result;
#elif defined(__x86_64__)
__asm__ volatile ("lock; cmpxchgq %3, %0; setz %1" : "=m"(*reg), "=q" (result) : "m" (*reg), "r" (newval + incre), "a" (oldval) : "memory");
return result;
#else
#error:architecture not supported and gcc too old
#endif
}
void *test_func(void *arg)
{
int i=0;
int result = 0;
for(i=0;i<2000;++i)
{
result = 0;
while(0 == result)
{
result = sync_add_and_fetch((int *)&count, count, 1);
}
}
return NULL;
}
int main(int argc, const char *argv[])
{
pthread_t id[10];
int i = 0;
for(i=0;i<10;++i){
pthread_create(&id[i],NULL,test_func,NULL);
}
for(i=0;i<10;++i){
pthread_join(id[i],NULL);
}
//10*2000=20000
printf("%u\n",count);
return 0;
}
يذهب الجواب مباشرة إلى 20000 ، لذلك أعتقد أنه عند استخدام وظيفة sync_add_and_fetch ، يجب أن تذهب مع حلقة while غبية ، لذلك أكتب مثل هذا:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
static unsigned long count = 0;
int compare_and_swap(int* reg, int oldval, int incre)
{
register char result;
#ifdef __i386__
__asm__ volatile ("lock; cmpxchgl %3, %0; setz %1" : "=m"(*reg), "=q" (result) : "m" (*reg), "r" (oldval + incre), "a" (oldval) : "memory");
return result;
#elif defined(__x86_64__)
__asm__ volatile ("lock; cmpxchgq %3, %0; setz %1" : "=m"(*reg), "=q" (result) : "m" (*reg), "r" (newval + incre), "a" (oldval) : "memory");
return result;
#else
#error:architecture not supported and gcc too old
#endif
}
void sync_add_and_fetch(int *reg,int oldval,int incre)
{
int ret = 0;
while(0 == ret)
{
ret = compare_and_swap(reg,oldval,incre);
}
}
void *test_func(void *arg)
{
int i=0;
for(i=0;i<2000;++i)
{
sync_add_and_fetch((int *)&count, count, 1);
}
return NULL;
}
int main(int argc, const char *argv[])
{
pthread_t id[10];
int i = 0;
for(i=0;i<10;++i){
pthread_create(&id[i],NULL,test_func,NULL);
}
for(i=0;i<10;++i){
pthread_join(id[i],NULL);
}
//10*2000=20000
printf("%u\n",count);
return 0;
}
ولكن عندما أقوم بتشغيل هذا الرمز باستخدام ./asm بعد g ++ -g -o asm asm.cpp -lpthread.the عالق للتو لأكثر من 5 دقائق ، انظر أعلى في محطة طرفية أخرى:
3861 root 19 0210m 888732 S 400 0.0 2: 51.06 asm
أنا فقط مرتبك ، أليس هذا الرمز هو نفسه؟