我正在尝试以向后兼容的方式从 C 中重新实现 RobotC API(尽管有一些细节,例如自动包含 stdbool、可选参数、引用、通过“数组”/下标符号值/赋值的 I/O,等更适合 C++,有些问题在 C++ 中可能更容易解决……)。这个包括void startTask(void TaskID, short nTaskPriority)
和 void stopTask(void TaskID)
启用多线程。
TaskID 旨在直接在新线程中运行的函数的名称。所以那里没有线程号变量,只有全局范围的函数名。我首先尝试使用宏标识符串联和外部变量来实现类似的东西,但我无法从函数内部定义全局变量(使用 extern
会导致声明而不是定义,并且默认情况下,函数中的定义在局部范围内),所以我最终得到的东西只能在同一范围内工作(或者从内部范围停止会起作用,但反之则不行)。
我怎么能做类似的事情呢?例如如何定义(例如使用一些复杂的宏技巧,gcc 扩展(虽然我更愿意尽可能保持标准,但如果这样的功能需要 gcc 也不会打扰太多),或者其他什么?) ,最好是多文件的、命名空间唯一的、虚构的变量,用于存储 pthread id?
#include <stdlib.h>
#include <pthread.h>
#include <stdarg.h>
#include <sched.h>
#include "misc.c"
const short kHighPriority = 255;
const short kLowPriority = 0;
const short kDefaultTaskPriority = 7;
/* void startTask(void TaskID,
short nTaskPriority = kDefaultTaskPriority) */
pthread_t
startTask (task (*TaskID)(void*), short nTaskPriority)
{
pthread_attr_t attr;
pthread_t thread;
struct sched_param param;
const int policy = sched_getscheduler(0),
sched_high_prio = sched_get_priority_max(policy), // 19,
sched_low_prio = sched_get_priority_min(policy), // -20,
sched_range_prio = sched_high_prio - sched_low_prio;
pthread_attr_init (&attr);
pthread_attr_getinheritsched(&attr, PTHREAD_INHERIT_SCHED);
pthread_attr_getschedparam (&attr, ¶m);
param.sched_priority = -(((nTaskPriority
- kLowPriority) * sched_range_prio
/ kHighPriority) + sched_low_prio);
pthread_attr_setschedparam (&attr, ¶m);
pthread_create (&thread, &attr, (void*) TaskID, NULL);
return thread;
}
void
stopTask (pthread_t thread)
{
pthread_cancel(thread);
}
void
stopAllTasks ()
{
exit(0);
}
#define startTask(task, priority) \
static pthread_t task##_thread = startTask(task, priority)
#define stopTask(task) \
stopTask(task##_thread)
理想情况下,我更愿意在没有外部(即非标准)库的情况下解决这个问题,在编译时,如果可能的话,使用 C 而不是 C++,标准(C11 不会打扰我),在这个order (!
gcc-specific ||
!
cxx ||
compile-time ||
stdc).
也就是说,除非找到其他东西,否则我可以使用 C++,甚至可以使用 GNU 扩展,并且完全可以使用 C/C++11 在编译时而不是运行时解决这个问题,例如 (虽然我的重新实现对我来说似乎大多是标准的,但需要 GNU 的全局范围多线程似乎并不过分)。
最佳答案
我会使用 dictionary .字典将键与值相关联。关键是这种情况下会将任务名称转换为字符串。该值将是来自 pthread_create
的线程 ID。
字典本身可以用任何你喜欢的方式实现:哈希表、二叉树、链表,甚至数组。字典接口(interface)由三个函数组成:Add()、Find() 和 Remove()。
要使用字典,startTask
和stopTask
宏使用#
运算符将函数名称转换为字符串。然后将该字符串传递给 StartTask
和 StopTask
函数,并用作字典中的 key
。
下面是一些演示这些概念的示例代码:
#include <stdio.h>
#include <stdbool.h>
#include <pthread.h>
#define startTask(task, priority) startTask(#task, task, priority)
#define stopTask(task) stopTask(#task)
void dictionaryAdd(char *key, pthread_t threadID)
{
printf("Adding key: %s\n", key);
// add the key with its associated threadID to the dictionary
}
bool dictionaryFind(char *key, pthread_t *threadID)
{
printf("Finding key: %s\n", key);
// find the key in the dictionary and get the associated threadID
*threadID = 0;
return true;
}
void dictionaryRemove(char *key)
{
// remove the key and associated value from the dictionary
printf("Removing key: %s\n", key);
}
void startTask(char *name, ...)
{
pthread_t threadID = 0;
pthread_create(&threadID, ...);
dictionaryAdd(name, threadID);
}
void stopTask(char *name)
{
pthread_t threadID;
if (dictionaryFind(name, &threadID))
{
pthread_cancel(threadID);
dictionaryRemove(name);
}
}
void *foo(void *arg)
{
return NULL;
}
int main(void)
{
startTask(foo, 10);
stopTask(foo);
}
代码的输出:
Adding key: foo
Finding key: foo
Removing key: foo
关于c++ - 通过宏从函数定义(并声明和使用)全局变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49458399/