所以我有一个任务,说我创建了一个2-d数组[5] [12],随机值在1-99之间。然后使用pthreads,我必须为数组中的每个元素添加1或减1,然后打印结果并将进程分成2,3或4个线程。线程数取决于用户在命令行上输入的内容。我有编译和运行的代码。但是,只有输入数字3时才会打印我想要的输出。你能告诉我我的代码出错了吗?我一开始很难理解pthreads。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include <pthread.h>
#include <iostream>
using namespace std;
int list[5][12];
int rows = 5;
int cols = 12;
int threadc;
void *threadf(void *arg)
{
int x = (int) arg;
for(int i = (x*60)/threadc; i < ((x+1) * 60)/threadc; i++)
{
for(int j = 0; j < 12; j++)
{
if (list[i][j] % 2 == 0)
list[i][j] += 1;
else
list[i][j] -= 1;
}
}
}
void cArray()
{
srand(time(NULL));
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 12; j++)
{
list[i][j] = rand() % 99 + 1;
}
}
}
void pArray(int list[][12], int rows, int cols)
{
cout << "\n";
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
{
cout << list[i][j] << " ";
}
cout << "\n";
}
}
int main(int argc, char *argv[])
{
if(argc != 2) exit(0);
threadc = atoi(argv[1]);
assert(threadc >= 2 && threadc <=4);
pthread_t *thread;
thread = new pthread_t [threadc];
if(thread == NULL)
exit(0);
cArray();
cout << "2-d Array: ";
pArray(list, rows, cols);
int t;
for(int i = 0; i < threadc; i++)
{
t = pthread_create(&thread[i], NULL, threadf, (void *)i);
if (t != 0)
return 1;
}
for(int i = 0; i < threadc; i++)
{
t = pthread_join(thread[i], NULL);
if(t != 0)
return 1;
}
cout << "Modified 2-d Array: ";
pArray(list, rows, cols);
return 0;
}
答案 0 :(得分:0)
让我们看看threadf
中的外部for循环,x = 0和threadc = 4
for(int i = (0*60)/4; i < ((0+1) * 60)/4; i++)
for(int i = 0; i < (1 * 60)/4; i++)
for(int i = 0; i < 60/4; i++)
for(int i = 0; i < 15; i++)
i
的范围是0到14.我的使用方式如下:list[i][j]
,请考虑写入list[14][11]
的位置。在int list[5][12];
定义的范围之外,将会出现Bad smurf。未定义的行为,所以在技术上没有人知道会发生什么。我们可以做一些相当不错的猜测。
int list[5][12];
int rows = 5; // probably overwritten by write to list[6][0]
int cols = 12; // probably overwritten by write to list[6][1]
int threadc; // probably overwritten by write to list[6][3]
所以row
和column
正在移动,但没有人关心。代码从不使用它们。但是threadc
......那个地方都在使用。实际上,它在循环退出条件中使用。这里可能会出现更多的不良情况。它还确定要创建和连接的线程数。可能无法创建某些线程。该程序可能会尝试加入比存在更多的线程。
无论如何,未定义的行为。我想我们都应该感到高兴的是,编译器没有生成下令进行战术核武攻击的代码。由于这是一个家庭作业问题,我不打算解释数学OP需要使他们的for
循环正确地分配多个线程的工作,但是会建议他们将数组视为一维数组大小为5 * 12,并在单个for
循环中进行1D-> 2D索引。
其他说明:
使用uintptr_t
代替int
代替i
main
和x
代threadf
。 uintptr_t
保证会转换为void *
对循环计数器和数组索引器使用类似size_t
的无符号变量。它们与uintptr_t
很好地匹配,你几乎不需要负数组索引。
使用std::vector
而不是指针和new
作为线程列表。如果您必须使用new
和指针,请记得在完成后删除列表。
看看您是否可以使用std::thread
代替pthread
。
将return
添加到threadf
。
答案 1 :(得分:-1)
当创建的线程数为2时,不知何故thread_join
会返回错误代码(在我的情况下为22
)。如果在第二个循环中删除return语句,程序将打印最终输出。
for(int i = 0; i < threadc; i++)
{
t = pthread_join(thread[i], NULL);
if (t != 0)
return 1; // <- your program works if you comment out this.
}
根据此链接:http://minirighi.sourceforge.net/html/errno_8h.html 22是EINVAL,意思是“线程不可连接”。
由于您关心pthread_join的返回值,我建议您在pthread_exit(NULL);
的末尾添加一个成功的终止函数(thredf
)。另外,为了避免@ user4581301提到的缓冲区溢出,您可以传递指向数据的指针。
所以thredf
就像
void *threadf(void *arg)
{
cout << endl;
int x = *((int*)arg); // <- NOTICE HERE!
for(int i = (x*60)/threadc; i < ((x+1) * 60)/threadc; i++)
//...
}
pthread_exit(NULL); // <- NOTICE HERE!
}
主要:
int main(int argc, char *argv[])
{
if(argc != 2) exit(0);
threadc = atoi(argv[1]);
assert(threadc >= 2 && threadc <=4);
pthread_t *thread;
thread = new pthread_t [threadc];
int *data = new int[threadc]; // <- NOTICE HERE!
if(thread == NULL)
exit(0);
cArray();
cout << "2-d Array: ";
pArray(list, rows, cols);
int t;
for(int i = 0; i < threadc; i++)
{
data[i] = i;
// NOTICE HERE!
t = pthread_create(&thread[i], NULL, threadf, (void *)(&data[i]));
if (t != 0)
return 1;
}
// ...