c++ - 通过宏从函数定义(并声明和使用)全局变量

标签 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 不会打扰我),在这个order (!gcc-specific || ! cxx || compile-time || stdc).

也就是说,除非找到其他东西,否则我可以使用 C++,甚至可以使用 GNU 扩展,并且完全可以使用 C/C++11 在编译时而不是运行时解决这个问题,例如 (虽然我的重新实现对我来说似乎大多是标准的,但需要 GNU 的全局范围多线程似乎并不过分)。

最佳答案

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

字典本身可以用任何你喜欢的方式实现:哈希表、二叉树、链表,甚至数组。字典接口(interface)由三个函数组成: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

关于c++ - 通过宏从函数定义(并声明和使用)全局变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49458399/

相关文章:

c++ - 给定源文件的 header "corresponding"是否有技术名称?

python - Python 中如何解析对变量的引用

c++ - 在指向另一个宏的可变参数宏中为每个参数添加前缀

C:在宏中隐藏 if 语句的最佳方法

c++ - C++中的宏和常量有什么区别?

c++ - 在循环内使用 list.push_back(),绕过使迭代器无效

c++ - 让 .natvis 将 SmartPointer<T> 显示为 static_cast<T*>(void*)

c++ - 在 C++ 中用更少的参数调用构造函数

c - 前向声明结构体的范围

ios - 如何在 Objective C 中创建一个强大的 boolean 值