这个函数是完全线程安全的吗?
EDIT3:每次需要时它都会在一个新线程中生成,“输入”是在其中释放的 char* 的副本。假设 cURL 函数是线程安全的。
EDIT4:假设任何不可见函数都是线程安全的。
static void *Com_GoogleTranslate(void* input) {
CURL *easy_handle;
char *pos1, *pos2, url[1024], final[1024], inlang[8], outlang[8], *encoded;
const int const_strlen = strlen("\"translatedText\":\"");
struct GoogleMem chunk;
pthread_mutex_lock( &GoogleMessage_mutex );
// 'auto' is really empty in google API:
if (!strcmp(clu.translateIn->string, "auto"))
strcpy(inlang, "");
else
strcpy(inlang, clu.translateIn->string);
if (!strcmp(clu.translateOut->string, "auto"))
strcpy(outlang, "");
else
strcpy(outlang, clu.translateOut->string);
pthread_mutex_unlock( &GoogleMessage_mutex );
// Build the URL
url[0] = '\0';
strcat(url, "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=");
// Encode input into URL formatting
encoded = url_encode((char*)input);
if (!encoded) return 0;
strcat(url, encoded);
strcat(url, "&langpair=");
strcat(url, inlang);
strcat(url, "|");
strcat(url, outlang);
chunk.memory = malloc(1); // realloc grows it at Com_GoogleTranslateMem()
if (!chunk.memory) return 0;
chunk.size = 0; // no data yet
// cURL initialization for this sub-session:
easy_handle = qcurl_easy_init();
// ioq3-urt: was needed on https:// (v2 API) attempts when using GnuTLS
//qcurl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, 3);
// set URL:
qcurl_easy_setopt(easy_handle, CURLOPT_URL, url);
// ioq3-urt: required for multithreading according to cURL doc.
qcurl_easy_setopt(easy_handle, CURLOPT_NOSIGNAL, 1);
// ioq3-urt: skip peer verification; required for google translate when SSL was used
//qcurl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
// send all data to this function
qcurl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, Com_GoogleTranslateMem);
// we pass our 'chunk' struct to the callback function:
qcurl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, (void *)&chunk);
// some servers don't like requests that are made without a user-agent field, so we provide one:
qcurl_easy_setopt(easy_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
// ioq3-urt: Required by Google Translate terms:
qcurl_easy_setopt(easy_handle, CURLOPT_REFERER, "ioq3-urt");
// fetch it
qcurl_easy_perform(easy_handle);
// cleanup curl stuff
qcurl_easy_cleanup(easy_handle);
/*
Now chunk.memory points to a memory block that is chunk.size
bytes big and contains the remote file.
Nothing has yet deallocated that data, hence free() is used at the end.
*/
if (!chunk.size) {
pthread_mutex_lock( &GoogleMessage_mutex );
sprintf(GoogleMessage.message, "Translation: no data received from Google\n");
GoogleMessage.new_message = qtrue;
pthread_mutex_unlock( &GoogleMessage_mutex );
// Free up memory (same with the end)
if(chunk.memory) free(chunk.memory);
free(encoded);
free(input);
return 0;
}
if ( ( pos1 = strstr(chunk.memory, "\"translatedText\":\"") ) ) { // Make sure we use a valid file:
pos2 = strstr(pos1 + const_strlen, "\""); // position translated text ends
// Build the translated text:
final[0] = '\0';
strncat(final, pos1 + const_strlen, strlen(pos1) - ( strlen(pos2) + const_strlen ) );
// Final printing of the translated text:
pthread_mutex_lock( &GoogleMessage_mutex );
sprintf(GoogleMessage.message, "^2Translated^7: ^3%s\n", final);
GoogleMessage.new_message = qtrue;
pthread_mutex_unlock( &GoogleMessage_mutex );
#ifdef BUILD_FREETYPE
TTF_Find_Slot(final, clu.TTF_MessageMaxTime->integer);
#endif
} else {
pthread_mutex_lock( &GoogleMessage_mutex );
sprintf(GoogleMessage.message, "Translation: no valid translation file received from Google\n");
GoogleMessage.new_message = qtrue;
pthread_mutex_unlock( &GoogleMessage_mutex );
}
// Free allocated memory
if(chunk.memory) free(chunk.memory);
free(encoded);
free(input);
return 0;
}
我仅在某些系统上出现不稳定的行为,虽然我怀疑其硬件有问题(英特尔 OpenGL?),但我想知道我是否遗漏了某些内容。
编辑:假设 cURL 本身是线程安全的。
EDIT2:“输入”是释放到该线程中的新副本。
EDIT3: It spawns in a new thread each time it is needed, "input" is a copy of a char* which is freed inside it. Assume cURL functions are thread safe.
EDIT4: Assume any non-visible functions are thread safe.
static void *Com_GoogleTranslate(void* input) {
CURL *easy_handle;
char *pos1, *pos2, url[1024], final[1024], inlang[8], outlang[8], *encoded;
const int const_strlen = strlen("\"translatedText\":\"");
struct GoogleMem chunk;
pthread_mutex_lock( &GoogleMessage_mutex );
// 'auto' is really empty in google API:
if (!strcmp(clu.translateIn->string, "auto"))
strcpy(inlang, "");
else
strcpy(inlang, clu.translateIn->string);
if (!strcmp(clu.translateOut->string, "auto"))
strcpy(outlang, "");
else
strcpy(outlang, clu.translateOut->string);
pthread_mutex_unlock( &GoogleMessage_mutex );
// Build the URL
url[0] = '\0';
strcat(url, "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=");
// Encode input into URL formatting
encoded = url_encode((char*)input);
if (!encoded) return 0;
strcat(url, encoded);
strcat(url, "&langpair=");
strcat(url, inlang);
strcat(url, "|");
strcat(url, outlang);
chunk.memory = malloc(1); // realloc grows it at Com_GoogleTranslateMem()
if (!chunk.memory) return 0;
chunk.size = 0; // no data yet
// cURL initialization for this sub-session:
easy_handle = qcurl_easy_init();
// ioq3-urt: was needed on https:// (v2 API) attempts when using GnuTLS
//qcurl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, 3);
// set URL:
qcurl_easy_setopt(easy_handle, CURLOPT_URL, url);
// ioq3-urt: required for multithreading according to cURL doc.
qcurl_easy_setopt(easy_handle, CURLOPT_NOSIGNAL, 1);
// ioq3-urt: skip peer verification; required for google translate when SSL was used
//qcurl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
// send all data to this function
qcurl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, Com_GoogleTranslateMem);
// we pass our 'chunk' struct to the callback function:
qcurl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, (void *)&chunk);
// some servers don't like requests that are made without a user-agent field, so we provide one:
qcurl_easy_setopt(easy_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
// ioq3-urt: Required by Google Translate terms:
qcurl_easy_setopt(easy_handle, CURLOPT_REFERER, "ioq3-urt");
// fetch it
qcurl_easy_perform(easy_handle);
// cleanup curl stuff
qcurl_easy_cleanup(easy_handle);
/*
Now chunk.memory points to a memory block that is chunk.size
bytes big and contains the remote file.
Nothing has yet deallocated that data, hence free() is used at the end.
*/
if (!chunk.size) {
pthread_mutex_lock( &GoogleMessage_mutex );
sprintf(GoogleMessage.message, "Translation: no data received from Google\n");
GoogleMessage.new_message = qtrue;
pthread_mutex_unlock( &GoogleMessage_mutex );
// Free up memory (same with the end)
if(chunk.memory) free(chunk.memory);
free(encoded);
free(input);
return 0;
}
if ( ( pos1 = strstr(chunk.memory, "\"translatedText\":\"") ) ) { // Make sure we use a valid file:
pos2 = strstr(pos1 + const_strlen, "\""); // position translated text ends
// Build the translated text:
final[0] = '\0';
strncat(final, pos1 + const_strlen, strlen(pos1) - ( strlen(pos2) + const_strlen ) );
// Final printing of the translated text:
pthread_mutex_lock( &GoogleMessage_mutex );
sprintf(GoogleMessage.message, "^2Translated^7: ^3%s\n", final);
GoogleMessage.new_message = qtrue;
pthread_mutex_unlock( &GoogleMessage_mutex );
#ifdef BUILD_FREETYPE
TTF_Find_Slot(final, clu.TTF_MessageMaxTime->integer);
#endif
} else {
pthread_mutex_lock( &GoogleMessage_mutex );
sprintf(GoogleMessage.message, "Translation: no valid translation file received from Google\n");
GoogleMessage.new_message = qtrue;
pthread_mutex_unlock( &GoogleMessage_mutex );
}
// Free allocated memory
if(chunk.memory) free(chunk.memory);
free(encoded);
free(input);
return 0;
}
I'm getting unstable behavior on certain system only and while I suspect its questionable hardware (Intel OpenGL?), I'd like to find out if I miss something.
EDIT: Assume cURL is thread safe in itself.
EDIT2: "input" is a new copy that is freed into this thread.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
对我来说,只要它在互斥锁保护部分之外调用的所有函数本身都是线程安全的,它看起来就是线程安全的。
然而,malloc 的线程安全性存在问题。请参阅此问题。
It looks thread safe to me as long as all the functions it calls outside of the mutex protected sections are themselves thread safe.
There is, however, a question over the thread safety of malloc. See this question.
这不是线程安全问题,但有一件事是一个突出的潜在问题。以下代码行不检查是否成功搜索:
如果
chunk.memory
值在"translatedText":"
值后面不包含另一个双引号,则它将为 null,并且strncat
内该值的后续strlen()
可能会导致访问冲突,至少添加
可能不会有什么坏处 是问题。
。但我不知道其他函数在做什么,如果它们保证双引号在字符串中,那么这也不 “我对所涉及的数据一无所知”问题是对所有适合 1024 缓冲区的字符串长度的盲目假设,从防御性编码的角度来看,对这些调用进行额外检查可能不会造成伤害,
否则,我同意(。 +1)与 JeremyP 一起,根据给定的代码,它看起来是线程安全的。
This is not a thread-safety issue, but there is one thing that stands out as a potential problem. The following line of code has no check for a successful search:
If the
chunk.memory
value did not contain another double quote following the"translatedText":"
value, then it would be null and the subsequentstrlen()
on that value inside thestrncat
would likely cause an access violation.At a minimum, it might not hurt to add an
assert
there to verify that it is indeed always succeeding. But I don't know what the other functions are doing. If they guarantee the double quote is in the string, then this is a non-issue.Also, from a "I don't know anything about the data involved" issue is the blind assumptions about string lengths all fitting in the 1024 buffers. From a defensive coding standpoint, additional checks on those calls might not hurt.
Otherwise, though, I agree (+1) with JeremyP that it looks thread safe based on the given code.