1.0 最简单, 最高效的方式


    C 代码运行起点 main 就是个大单例函数. 如果把函数注册在其里面, 那么一定很可以 :)
// 某个库需要初始化的函数
void log_init(void) {
... ...
} int main(int argc, char * argv[]) {
... ...
extern void log_init(void);
log_init()
... ...
return 0;
}
是不是, 很轻松的完成了初始化工作.
不妨赠送一个好用的宏, 用于处理这类事情
//
// EXTERN_RUN - 简单的声明, 并立即使用的宏
// ftest : 需要执行的函数名称
// ... : 可变参数, 保留
//
#define EXTERN_RUN(ftest, ...) \
do { \
extern void ftest(); \
ftest (__VA_ARGS__); \
} while(0)
用起来更简单, 可以插在代码的任何一处
EXTERN_RUN(log_run);

2.0 多线程模式, 如何搞起呢


    继续看下面例子 once.c
#include <stdio.h>
#include <pthread.h> static void _once(void) {
static long _cnt; printf("_once _cnt = %ld\n", ++_cnt);
} //
// pthread_once 感受
//
int main(int argc, char * argv[]) {
pthread_once_t once = PTHREAD_ONCE_INIT; puts("pthread_once 感受开始 ... ");
pthread_once(&once, _once);
pthread_once(&once, _once);
puts("pthread_once 感受结束 ... "); return 0;
}
gcc -g -Wall -o once.out once.c -lpthread
最终运行结果, 也是如我们所料那样

pthread_once 实际开发中多用于初始化线程私有变量. 其内部实现加锁的.
不妨问个小问题, 如果需要你去实现 pthread_once 你会怎么分析呢 ? 这个问题好解答也不好解答.
核心亮点在于 pthread_once 运行的函数实体崩溃了. 多线程之间如何避免死锁.
不妨参照下面 winds 上面 pthread_once 一位大佬的实现:
#include "pthread.h"
#include "implement.h" /* [i_a] simple wrapper ensures correct calling convention for all */
static void PTW32_CDECL
ptw32_mcs_lock_cleanup(void *args)
{
ptw32_mcs_local_node_t *node = (ptw32_mcs_local_node_t *)args;
ptw32_mcs_lock_release(node);
} int
pthread_once (pthread_once_t * once_control, void (PTW32_CDECL *init_routine) (void))
{
if (once_control == NULL || init_routine == NULL)
{
return EINVAL;
} if ((PTW32_INTERLOCKED_LONG)PTW32_FALSE ==
(PTW32_INTERLOCKED_LONG)PTW32_INTERLOCKED_EXCHANGE_ADD_LONG((PTW32_INTERLOCKED_LONGPTR)&once_control->done,
(PTW32_INTERLOCKED_LONG)0)) /* MBR fence */
{
ptw32_mcs_local_node_t node; ptw32_mcs_lock_acquire((ptw32_mcs_lock_t *)&once_control->lock, &node); if (!once_control->done)
{ #if defined(PTW32_CONFIG_MSVC7)
#pragma inline_depth(0)
#endif pthread_cleanup_push(ptw32_mcs_lock_cleanup, &node);
(*init_routine)();
pthread_cleanup_pop(0); #if defined(PTW32_CONFIG_MSVC7)
#pragma inline_depth()
#endif once_control->done = PTW32_TRUE;
} ptw32_mcs_lock_release(&node);
} return 0; } /* pthread_once */
核心是通过 pthread_cleanup_push 和  pthread_cleanup_pop 解决崩溃死锁问题.
当然还有一种思路, 可以解决上面问题. 不妨往下看.

3.0 跳过锁问题, 尝试原子操作


    先举个小例子
#include <stdio.h>

static void _once(void) {
static long _cnt; printf("_once _cnt = %ld\n", ++_cnt);
} //
// run once 感受
//
int main(int argc, char * argv[]) {
puts("run once 感受开始 ... "); {
static int _done;
if (__sync_bool_compare_and_swap(&_done, 0, 1)) {
_once();
} if (__sync_bool_compare_and_swap(&_done, 0, 1)) {
_once();
}
} puts("run once 感受结束 ... ");
return 0;
}
运行展示:

这里通过 GCC 提供的 原子交换 __sync_bool_compare_and_swap 解决的. 

不妨继续赠送的封装宏, 来完成上面操作
#define ONCE_RUN(code) {                                    \
static int _done; \
if (!_done) { \
if (__sync_bool_compare_and_swap(&_done, 0, 1)) { \
code \
} \
} \
}
因为是原子操作, 没有锁那么重, 自然出了问题也不会引起死锁问题.  

当然有人说 pthread, __sync_xxx 都是和 GCC 绑定的, 那么 CL 能不能使用了. 当然也是可以的.

pthread 跨平台 - https://github.com/wangzhione/structc/blob/master/structc/system/thread.h

atomic 跨平台 - https://github.com/wangzhione/atomic/blob/master/atomic/atom.h

通过上面基础封装库支持, 用 C 写系统应用相关代码还是很好搞的.

把酒满上, 还能再写几行代码

    有问题, 是肯定的. 欢迎指正, 更新是共同提高的过程.

老鼠爱大米 - http://music.163.com/m/song?id=308789&userid=16529894

回头看看, 时间好快呀.  那些个一块补习, 为了玩的伙伴们, 二胎孩子都快上学了.
哈哈.
咱们一线秃头兵还在为了 穷 而冲锋陷阵 (°ー°〃)

C基础 如何让代码只执行一次的更多相关文章

  1. 小技巧--让JS代码只执行一次

    有时候实在是没办法,就像我这个比赛系统中,有一个弹出框,这个弹出框之外都是模糊的(这是在ajax写出弹出框时,加了一个水印). 然而遇到的问题,也是蹊跷古怪,因为这个弹出框的事件是数据查询事件,但是因 ...

  2. Web下TreeView同一节点连续点击,只执行一次SelectedNodeChanged的解决

    Web下TreeView同一节点连续点击,只执行一次SelectedNodeChanged的解决 http://blog.csdn.net/net_boy/archive/2009/11/05/477 ...

  3. 新版本的jquery checkbox 全选反选代码只能执行一遍,第二次就失败attr与prop区别

    $("#all_check").click(function() { $("input[name='checkShop[]']").attr("che ...

  4. js函数只执行一次,函数重写,变量控制与闭包三种做法

    一.情景需求 调用后台接口需要附带token信息,那么在每个请求的头部添加token的做法就不太优雅了:一个网站请求100次,那就得写添加100次token,假设某天接口有所变动,改起来就十分麻烦了. ...

  5. java for循环里面执行sql语句操作,有效结果只有一次,只执行了一次sql mybatis 循环执行update生效一次 实际只执行一次

    java后台controller中,for循环执行数据库操作,但是发现实际仅仅执行了一次,或者说提交成功了一次,并没有实际的个数循环 有可能是同一个对象导致的 可以仔细看一下下面两段代码有什么区别 p ...

  6. selenium+python+unittest:一个类中只执行一次setUpClass和tearDownClass里面的内容(可解决重复打开浏览器和关闭浏览器,或重复登录等问题)

    unittest框架是python自带的,所以直接import unittest即可,定义测试类时,父类是unittest.TestCase. 可实现执行测试前置条件.测试后置条件,对比预期结果和实际 ...

  7. java中的static代码块为什么只执行一次

    原因在最后,这是其中的一个小例子. 如: SessionFactory负责保存和使用所有配置信息,消耗内存资源非常大 所以一个web项目要保证只创建一个SessionFactory 那么在使用hibe ...

  8. shell 脚本中 while 只执行一次

    实例代码 while read line ; do ssh -p20002 $line -o StrictHostKeyChecking=no xxxxxxxxx done < ip.txt w ...

  9. jquery checkbox 全选反选代码只能执行一遍,第二次就失败

    遇到问题背景: 在写到购物车的全选交互的时候,商品选中的状态只有在第一次的时候可以,第二次就无法选中:(代码如下) $(".chooseall").click(function() ...

随机推荐

  1. 使用Runtime.getRuntime().exec()方法的几个陷阱

    Process 子类的一个实例,该实例可用来控制进程并获得相关信息.Process 类提供了执行从进程输入.执行输出到进程.等待进程完成.检查进程的退出状态以及销毁(杀掉)进程的方法. 创建进程的方法 ...

  2. 【数据库_Mysql】<foreach>标签在Mysql中的使用

    foreach属性 属性 描述 item 循环体中的具体对象.支持属性的点路径访问,如item.age,item.info.details.具体说明:在list和数组中是其中的对象,在map中是val ...

  3. Linux(三)高级文本处理命令

    一.cut (cut 命令可以从一个文本文件或者文本流中提取文本列 ) 1.cut语法 cut -d '分隔字符' -f fields         用于有特定分隔字符 cut  -c 字符区间   ...

  4. java类加载过程以及双亲委派机制

    前言:最近两个月公司实行了996上班制,加上了熬了两个通宵上线,状态很不好,头疼.牙疼,一直没有时间和精力写博客,也害怕在这样的状态下写出来的东西出错.为了不让自己荒废学习的劲头和习惯,今天周日,也打 ...

  5. 实例讲解启动mysql server失败的解决方法

    MySQL 实例讲解启动mysql server失败的解决方法 来源: 作者: 发表于: 启动mysql server 失败,查看/var/log/mysqld.err 080329 16:01:29 ...

  6. 手脱nSPack 3.7

    方法一: 1.   OD查壳—nSpack3.7的壳 2. 载入OD 看起来很眼熟,F8一次,然后下面就可以使用ESP定律了,使用ESP定律下断点,然后F9四次 3.   F9四次后落到这个位置 接下 ...

  7. Linux安全之SYN攻击原理及处理

    TCP自从1974年被发明出来之后,历经30多年发展,目前成为最重要的互联网基础协议,但TCP协议中也存在一些缺陷. SYN攻击就是利用TCP协议的缺陷,来导致系统服务停止正常的响应. SYN攻击原理 ...

  8. git 从新的git 库中拉取---变换git地址用;

    2.先删后加 git remote rm origin git remote add origin [url]----- example :   git remote add origin http: ...

  9. P1801 黑匣子_NOI导刊2010提高(06)

    P1801 黑匣子_NOI导刊2010提高(06) 题目描述 Black Box是一种原始的数据库.它可以储存一个整数数组,还有一个特别的变量i.最开始的时候Black Box是空的.而i等于0.这个 ...

  10. myeclipse注册机,自己生成注册码

    话不多少,直接上代码 直接可以运行,自己输入key即可 package com.generate.myeclipse.code; import java.io.BufferedReader; impo ...