c - pthread void 指针转换
问题描述
我正在处理一项任务,该任务要求我使用线程来处理和同步从文件中获取数据。我的教授告诉我,我可以将我的数据更改为 void 指针以将其传递给我的函数,然后将其转换回来。我正在尝试使用文件 IO 来做到这一点。
pthread_create(&th1, NULL, processing, (void *)&fp);
在我的处理函数中,我试图将其转换回 FILE 指针:
FILE driveOne = (FILE *)file;
这显然不起作用,所以有人可以向我解释一下吗?
解决方案
这是一个更完整的例子。
假设您的工作函数需要一个文件句柄。为简单起见,假设它从中读取每个字符,并返回读取的字符数,转换为指针:
void *worker(void *data)
{
FILE *handle = (FILE *)data;
uintptr_t count = 0;
if (handle && !ferror(handle)) {
/* handle is a valid file handle */
while (getc(handle) != EOF)
count++;
}
return (void *)count;
}
如果是orcount
以外的其他类型(在 中声明,通常包含在 include中),您需要先将其转换为该类型,然后再转换为 void 指针,即.intptr_t
uintptr_t
<stdint.h>
<inttypes.h>
(void *)(uintptr_t)count
因为这样的工作线程不需要太多的堆栈(准确地说几乎没有),而且默认的线程堆栈大小很大(兆字节),我们可以节省一些内存(如果需要,可以允许更多的线程,尤其是在 32 位架构上) 通过创建一个指示pthread_create()
使用较小堆栈的 pthread 属性。该属性不被调用“消耗”;它更像是一个配置块。
假设您有三个流 ,FILE *in[3];
并且您希望使用三个线程来检查它们的长度。使用 pthread 属性来使用较小的堆栈(2*PTHREAD_STACK_MIN
定义在 中<limits.h>
,对于不使用alloca()
或本地数组的工作线程来说是一个很好的、安全的值。):
pthread_t worker_id[3];
uintptr_t length[3];
pthread_attr_t attrs;
void *retptr;
int i, result;
/* Create a pthread attribute set, defining smaller stack size. */
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, 2*PTHREAD_STACK_MIN);
/* Create the three worker threads. */
for (i = 0; i < 3; i++) {
result = pthread_create(&(worker_id[i]), &attrs, worker, (void *)in[i]);
if (result) {
fprintf(stderr, "Cannot create thread: %s.\n", strerror(result));
exit(EXIT_FAILURE);
}
}
/* pthread attributes are no longer needed. */
pthread_attr_destroy(&attrs);
/*
... This thread can do something else here ...
*/
/* Reap the threads, and collect their return values. */
for (i = 0; i < 3; i++) {
result = pthread_join(worker_id[i], &retptr);
if (result) {
fprintf(stderr, "Cannot reap thread: %s.\n", strerror(result));
exit(EXIT_FAILURE);
}
length[i] = (uintptr_t)retptr;
}
for (i = 0; i < 3; i++)
printf("in[%d] contained %llu chars.\n", i, (unsigned long long)length[i]);
当您想将多个参数传递给线程函数时,可以使用相同的模式。您首先构建一个结构来保存这些参数,然后创建它们。您可以动态分配它们,将它们声明为全局变量,或在 main() 中将它们声明为局部变量——在工作线程存在的整个持续时间内存在的任何范围都可以工作。
例如,假设您的工作函数计算unsigned char
从流中读取的每个值的直方图:
struct work {
pthread_t id; /* Thread identifier */
FILE *in; /* File handle to read from */
size_t count[UCHAR_MAX + 1]; /* Histogram */
};
void *worker(void *data) {
struct work *const work = (struct worker_data *)data;
int c;
if (!work || !work->in) {
/* Invalid data, or invalid file handle. */
return (void *)(intptr_t)(EINVAL);
}
if (ferror(work->in)) {
/* Stream is in error state. */
return (void *)(intptr_t)(EIO);
}
/* Read the stream. */
while ((c = getc(work->in)) != EOF) {
/* Update histogram. */
work->count[(unsigned char)c]++;
}
/* Did the reading stop due to an I/O error? */
if (ferror(work->in))
return (void *)(intptr_t)(EIO);
/* No errors, all done. */
return (void *)0;
}
请注意,struct work *const work = ...
初始化一个常量指针work
,而不是一个指向常量的指针。只有const
一个优化告诉 C 编译器我们不会尝试修改work
指针本身。它指向的数据是可修改的。
(要阅读指针声明,请从右到左阅读它们,将每个声明替换*
为"is a pointer to",以获得正确的含义。)
创建这些工作人员的代码非常相似,只是我们动态分配工作:
struct work *work[3];
pthread_attr_t attrs;
void *retptr;
int i, result;
/* Create and initialize the three pointers. */
for (i = 0; i < 3; i++) {
/* Allocate a work structure. */
work[i] = malloc(sizeof *(work[i]));
if (!work[i]) {
fprintf(stderr, "Out of memory.\n");
exit(EXIT_FAILURE);
}
/* Copy the handle to read from, */
work[i]->in = in[i];
/* and clear the histogram part. */
memset(work[i]->count, 0, sizeof work[i]->count);
}
/* Create a pthread attribute set, defining smaller stack size. */
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, 2*PTHREAD_STACK_MIN);
/* Create the three worker threads. */
for (i = 0; i < 3; i++) {
result = pthread_create(&(work[i]->id), &attrs, worker, (void *)work[i]);
if (result) {
fprintf(stderr, "Cannot create thread: %s.\n", strerror(result));
exit(EXIT_FAILURE);
}
}
/* pthread attributes are no longer needed. */
pthread_attr_destroy(&attrs);
/*
... This thread can do something else here ...
*/
/* Reap the threads, and collect their return values. */
for (i = 0; i < 3; i++) {
result = pthread_join(work[i]->id, &retptr);
if (result) {
fprintf(stderr, "Cannot reap thread: %s.\n", strerror(result));
exit(EXIT_FAILURE);
}
/* If the thread reported a failure, print the corresponding
error message (but do not exit). */
if (retptr)
fprintf(stderr, "Thread %d of 3: %s.\n", i+1, strerror((intptr_t)retptr));
/* ... print the histogram here? ... */
}
/* Free the work structures. */
for (i = 0; i < 3; i++)
free(work[i]);
如果您不想在发生错误时中止程序,注意它free(NULL)
是安全的并且什么都不做是有用的;并struct work *pointerarray[SIZE] = {0};
声明一个指向 的 SIZE 指针数组struct work
,并将它们全部初始化为零。例如,如果分配或线程创建在某个时候失败,您可以只使用free()
每个指针,无论其分配是否成功。
也就是说,如果你想分配三种不同类型的结构(struct atype *a;
、struct btype *b;
和struct ctype *c;
),你可以这样做
a = malloc(sizeof *a);
b = malloc(sizeof *b);
c = malloc(sizeof *c);
if (!a || !b || !c) {
free(c);
free(b);
free(a);
return ALLOCATION_FAILED;
}
/* Allocation was successful */
而不是分配每一个并分别测试失败。
推荐阅读
- python - ModuleNotFoundError:没有名为“allennlp.data.iterators”的模块
- c# - EntityFramework Core 中的 SQL 元组比较
- javascript - 使用 node.js 服务器和反应应用程序的 POST 请求错误抛出 404
- sql - 用于自动更改列类型的 PLSQL 过程
- sql - 在 Oracle 的上标中显示带有 st,nd,rd 的日期
- azure-active-directory - Msal.js 2.2 PKCE 授权流程刷新令牌丢失
- shell - 如何简化和提高我的条件?
- git - 从备份文件恢复 GitLab 存储库
- julia - 使用绘图在单独的窗口中显示两个绘图
- .net-core - Log4net 无法与 netcore 编写的 Windows 服务一起使用