从函数到宏定义(并声明和使用)全局变量

时间:2018-03-23 21:17:19

标签: c++ scope macros pthreads global-variables

我正在尝试以向后兼容的方式重新实现来自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, &param);
  param.sched_priority = -(((nTaskPriority
                             - kLowPriority) * sched_range_prio
                            / kHighPriority) + sched_low_prio);
  pthread_attr_setschedparam (&attr, &param);
  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的全局范围多线程似乎并不太多。)

1 个答案:

答案 0 :(得分:1)

我会使用dictionary。字典将键与值相关联。关键是这种情况会由任务名称转换为字符串。值为pthread_create的线程ID。

字典本身可以以您喜欢的方式实现:哈希表,二叉树,链表,甚至数组。字典界面由三个函数组成:Add(),Find()和Remove()。

要使用字典,startTaskstopTask宏会使用#运算符将函数名称转换为字符串。然后,该字符串将传递给StartTaskStopTask函数,并用作字典中的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