这应该是一项简单的任务,但我就是无法让它工作。下面的代码应该是不言自明的,我试图创建4个线程,每个线程都打印我在printMessage中定义的数组中的不同字符串。
#include <pthread.h>
#include <iostream>
using namespace std;
void *printMessage(void *arg)
{
int argInt = *((int*) arg);
const char* my_messages[4] = {"English: Hello!",
"French: Bonjour!", "Spanish: Hola!",
"German: Guten Tag!" };
cout << my_messages[argInt] << "n";
pthread_exit(0);
}
int main()
{
pthread_t id[4];
int rc;
// Create thread(s)
for(int i = 0; i < 4; i++) {
int index = i;
rc = pthread_create(&id[index], NULL, printMessage, (void*) &index);
if (rc) {
cout << "ERROR; return code from pthread_create() is " << rc << endl;
return -1;
}
}
pthread_exit(0);
}
当执行此操作时,数组中的最后一个字符串";德语:Guten Tag"打印了4次。我注意到的另一个奇怪的情况是,如果我放弃看似多余的"index"变量,转而使用"I",则不会打印任何内容。作为一个刚接触c++和多线程的人,这对我来说非常困惑,任何帮助都将不胜感激。谢谢
您将int index
定义为循环体内部的局部变量,因此在pthread_create()
退出后,它将超出范围,因此printMessage()
通过访问无效内存表现出未定义的行为(内存可能在每次循环迭代中被重用(。
您需要:
- 将
index
值移动到循环之前声明的数组中,并保持在作用域中,直到所有线程都终止为止。就像您对id[]
阵列所做的那样
#include <pthread.h>
#include <iostream>
using namespace std;
void* printMessage(void *arg)
{
int argInt = *static_cast<int*>(arg);
const char* my_messages[4] = {"English: Hello!",
"French: Bonjour!", "Spanish: Hola!",
"German: Guten Tag!" };
cout << my_messages[argInt] << "n";
return NULL;
}
int main()
{
pthread_t id[4];
int index[4];
int rc, num = 0;
// Create thread(s)
for(int i = 0; i < 4; i++) {
index[i] = i;
rc = pthread_create(&id[i], NULL, printMessage, &index[i]);
if (rc) {
cout << "ERROR; return code from pthread_create() is " << rc << endl;
break;
}
++num;
}
// wait for threads to terminate ...
for(int i = 0; i < num; i++) {
pthread_join(id[i], NULL);
}
return 0;
}
- 将
index
的值传递到每个线程,而不是向index
传递指针
#include <pthread.h>
#include <iostream>
using namespace std;
void* printMessage(void *arg)
{
int argInt = reinterpret_cast<int>(arg);
const char* my_messages[4] = {"English: Hello!",
"French: Bonjour!", "Spanish: Hola!",
"German: Guten Tag!" };
cout << my_messages[argInt] << "n";
return NULL;
}
int main()
{
pthread_t id[4];
int rc, num = 0;
// Create thread(s)
for(int i = 0; i < 4; i++) {
rc = pthread_create(&id[i], NULL, printMessage, reinterpret_cast<void*>(i));
if (rc) {
cout << "ERROR; return code from pthread_create() is " << rc << endl;
break;
}
++num;
}
// wait for threads to terminate ...
for(int i = 0; i < num; i++) {
pthread_join(id[i], NULL);
}
return 0;
}
- 动态分配
index
,并让线程销毁它传递的int
#include <pthread.h>
#include <iostream>
using namespace std;
void* printMessage(void *arg)
{
int *argInt = static_cast<int*>(arg);
const char* my_messages[4] = {"English: Hello!",
"French: Bonjour!", "Spanish: Hola!",
"German: Guten Tag!" };
cout << my_messages[*argInt] << "n";
delete argInt;
return NULL;
}
int main()
{
pthread_t id[4];
int rc, num = 0;
// Create thread(s)
for(int i = 0; i < 4; i++) {
int *index = new int(i);
rc = pthread_create(&id[i], NULL, printMessage, index);
if (rc) {
cout << "ERROR; return code from pthread_create() is " << rc << endl;
delete index;
break;
}
++num;
}
// wait for threads to terminate ...
for(int i = 0; i < num; i++) {
pthread_join(id[i], NULL);
}
return 0;
}
话虽如此,您确实应该直接使用std::thread
而不是pthreads
(如果std::thread
实现需要,可以在内部使用pthreads
(:
#include <iostream>
#include <thread>
using namespace std;
void printMessage(int arg)
{
const char* my_messages[4] = {"English: Hello!",
"French: Bonjour!", "Spanish: Hola!",
"German: Guten Tag!" };
cout << my_messages[arg] << "n";
}
int main()
{
thread thrd[4];
// Create thread(s)
for(int i = 0; i < 4; i++) {
thrd[i] = thread(printMessage, i);
}
// wait for threads to terminate ...
for(int i = 0; i < 4; i++) {
thrd[i].join();
}
return 0;
}
rc = pthread_create(&id[index], NULL, printMessage, (void*) &index);
这将创建一个新的执行线程,并将一个指向名为index
的局部变量的指针作为其参数传递给它。
无论如何,您绝对不能保证新的执行线程实际上在pthread_create
返回之前开始执行,或者在返回之后立即开始执行。通常情况下,在新的执行线程启动之前会有一个小延迟。您所能保证的是,新的执行线程将很快开始运行。
同时,pthread_create()
返回,到达循环的末尾,指针传递到的index
变量被破坏,它消失在一个黑洞中,再也看不到了。一段时间后,新的执行线程开始翻腾,得到它的线程参数,该参数现在指向一个已销毁的对象。未定义的行为。
你有几个选择。
使用
new
在动态范围中分配线程参数(并在执行线程delete
完成后将其作为new
对象(。使用额外的多线程资源,如互斥和条件变量,来协调创建新执行线程所涉及的歌曲和舞蹈,以便父执行线程等待,直到新执行线程读取其参数,并将其放在手边。