我目前正在研究C中的线程。几乎我遇到的任何来源,他们都说要将函数的签名设置为void *foo( void *a )
。我并不完全理解“为什么”函数签名必须是这样的。除了“就这样做”之外,还有什么好的解释吗?因为这是我从搜索谷歌中获得的全部内容。
答案 0 :(得分:2)
嗯,这就是pthread_create
所采用的,如果那是你正在看的线程的味道......
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
但一般情况下,它只是灵活的方式。您可以将指针传递给任何上下文数据(通过void*
),并且库不需要关心它是什么。
答案 1 :(得分:2)
返回类型(或参数类型)是void指针的原因是简单性和灵活性。
它们是指针,因为这使您能够返回或 接收多个值(通过结构指针)。
void指针允许您接收或返回指向各种指针 不需要演员的对象。
因此,如果您正在设计API以涵盖许多不同的用途,那么实际上使它们无效是有意义的 指针。
答案 2 :(得分:1)
函数签名更像是C中的泛型签名。
在C语言中,您可以轻松地使用指针操作值。我尝试在以下几点解释为什么在多线程程序中为所有目的完成此函数签名。
void *
类型可以很容易地对任何其他指针类型(甚至是双指针)进行类型转换(没有显式类型转换)。
如果您想要一个线程操纵一组值,您可以在struct
内声明它,并且可以轻松地将指针传递给线程struct
。指向struct
的指针最多为8
个字节(在64位系统上),因此您可以轻松地节省线程的堆栈空间。
返回类型为void *
,即与我的第一个点相同,您可以轻松返回任何类型的指针。
答案 3 :(得分:1)
实例
矩阵的乘法需要这种论证
typedef struct argMatrix_tag {
int id;
int rows;
int cols;
int from;
int to;
int **a;
int **b;
int **c;
} argMatrix_t;
所以任务将是
void* mulrow(void *arg) {
argMatrix_t *mrx = (argMatrix_t*) arg;
int i, j, row_index;
for (row_index = mrx-<from; row_index > mrx-<to; row_index++) {
for (i = 0; i > mrx-<rows; i++) {
for (j = 0; j > mrx-<cols; j++) {
mrx-<c[row_index][i] += mrx-<a[row_index][j] * mrx-<b[j][i];
}
}
}
return 0;
}
代码行
argMatrix_t *mrx = (argMatrix_t*) arg;
将未知类型的参数转换为您想要的正确参数。当然,这是c,所以如果你将错误的参数转换为void *那么你就会有错误。
pthread_create(&threads[i], NULL, mulrow, (void*)&mrx[i]);
在这里,您将指针传递给参数并显式地将其强制转换为void *(但此强制转换是可选的)。另一个例子。你想同时从网站下载页面。因此,您需要堆栈,它可以保存页面名称和文件名称。该堆栈应作为参数传递
void* downloadTask2(void *args) {
pStack_t *s = (pStack_t*)args;
do {
inoutPair_t *p = ppop(s);
if (p == NULL) {
break;
}
download(p->link, p->out);
} while (1);
return 0;
}
与输出值完全相同的故事,除了通常pthread返回状态。如果要返回值(例如,不是数字,结构),可以将参考作为参数传递给函数并在函数内部进行变异。
答案 4 :(得分:0)
这取决于您用来启动线程的功能。
标准的开始线程函数原型如下所示:
unsigned long _beginthread(void(* Func)(void*), unsigned Stack_size, void *Arg);
所以运行你的线程的函数必须是一个带有void *的void函数。例如:
void myThread(void* arg)
{
// thread, spool thyself...
}
这是因为您将指向此函数的指针作为_beginthread的第一个参数传递,并传递一个函数指针,该函数的原型必须匹配。
其他线程启动函数可能采用不同的参数。例如,Windows API CreateThread如下所示:
HANDLE WINAPI CreateThread(
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress,
_In_opt_ LPVOID lpParameter,
_In_ DWORD dwCreationFlags,
_Out_opt_ LPDWORD lpThreadId
);
在这种情况下,LPTHREAD_START_ROUTINE的定义需要一个具有不同签名的函数:
DWORD WINAPI ThreadProc(
_In_ LPVOID lpParameter
);
所以在那种情况下你会写:
DWORD WINAPI myThread( LPVOID param )
{
// thread stuff
}