我正在尝试以向后兼容的方式重新实现来自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不会打扰我),如果可能的话,订单(!
gcc特定的||
!
cxx ||
编译时||
stdc)。
也就是说,除非找到别的东西,我对C ++没问题,更多的是使用GNU扩展,并且完全可以使用C / C ++ 11在编译时解决这个问题,而不是运行时(例如)虽然我的重新实现对我来说似乎是标准的,但需要GNU的全局范围多线程似乎并不太多。)
答案 0 :(得分:1)
我会使用dictionary。字典将键与值相关联。关键是这种情况会由任务名称转换为字符串。值为pthread_create
的线程ID。
字典本身可以以您喜欢的方式实现:哈希表,二叉树,链表,甚至数组。字典界面由三个函数组成: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