葡京国际平台C基础 如何被代码只实行同一不良

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);

文章由作者马志国在博客园之原创,若转载请给大庭广众处于标记出处:http://www.cnblogs.com/mazg/

相应之视频教程地址(土豆网):http://list.youku.com/albumlist/show/id_51453937.html

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 解决崩溃死锁问题.
当然还有一种思路, 可以解决上面问题. 不妨往下看.

1.1 编译环境及开发工具

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

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

1.1.1 Go语言编译器

下载地址:http://liteide.org/cn/doc/install/

出于Go语言支持Windows、mac和Linux等主流操作系统,所以我们要基于操作系统选择不同的设置包文件。以win10 64位操作系统为条例,选择的装包文件为:go1.8.3.windows-amd64.msi。点击默认安装即可。

搭下去,配置环境变量GOPATH。右击”此电脑”选择属性,然后择左边列表中的尖端系统安装,接下当弹出的对话框中点击环境变量按钮。在系统变量中,点击新建按钮。在弹出的对话框中,变量名写GOPATH,变量值写设置的Go项目路线。

 Go项目路线下约定来三单子目录:

1) src 存放源代码(比如:.go .c .h .s相当)

2) pkg存放编译后生成的文书(比如:.a)

3) bin 存放编译后生成的可执行文件(为了推行好,可以将这目录在到 path 环境变量蒙)

 Go常用之老三单命:

  1. go run:直接运行程序
  2. go build:编译生成可执行程序
  3. go get:获取远程包(需提前安装
    git或hg)

 

1.1.2 LiteIDE

下载地址:http://liteide.org/cn/

LiteIDE是同等悠悠简单,开源,跨平台的Go IDE。

同样因为win10 64各类操作系统也例,选择的装包文件呢:liteidex32.2.windows-qt5.zip。直接解压,在其间的bin目录下,点击liteide.exe即可运行。

再也安GOPATH后,liteIDE不见面自动更新,也亟需再设置”查看”->”编辑时条件”。Go工具对管的追寻打src目录开始。

 

1.1.3 Git工具

下载地址:https://git-scm.com/download/win

因win10 64各项操作系统为条例,选择的装包文件呢:Git-2.8.1-64-bit.exe。  

采用Git工具得到Go的远程包。Git是一律款款免费、开源的分布式版本控制系统,方便之打https://github.com/收获源代码。gitHub是一个面向开源和个人软件类之托管平台,因为只支持git
作为唯一的本子库格式进行托管,故曰gitHub。

 

1.2 第一个Go程序

因为民俗的“Hello World”为例,开始Go语言编程的一起。

 

package main

import "fmt"

func main() {
fmt.Println("Hello 世界")
}

 

 代码解读:

每个Go源文件还因相同长package声明语句开始,表示该源文件属于哪个包。包类似于其它语言的库房或者模块。这个例子也package main。main包比较异常,它定义了一个单独可尽的程序,而休是仓库。

继之是同等文山会海导入包语句,用于导入该次所据的管。由于本示例程序用到了Println()函数,所以需要导入该函数所属之fmt包。需要小心的凡,不能够包含在源代码中无下的保,否则Go编译器会报编译错误。

以main包,有以只是来一个main( )函数,是Go程序执行的进口。在main()函数中调用Println()函数打印输出 Hello,世界。我们特意利用了汉语“世界”,这意味Go语言原生支持Unicode,可以拍卖全世界任何语言的公文。另外,Go语句不需加分号表示晓句子结束。在Go语言中,所有函数以重要字func开头。一个健康的函数定义包含以下一些:

func 函数号称(参数列表)(返回值列表){

    //函数体

}

 而main函数既无参数,也未尝回值。

Go代码注释与C语言保持一致,同时支持以下简单种植用法:

//行注释

/*

片注释即多执行注释

*/

示范go build go install go
run命令,并较其分别。

go build 编译包,并且以当前目录下生成可执行文件

go run 直接运行,但令后以及的凡文件,而不是目录(包)

go install 会在src同级目录下的package目录下生成.a包文件,在同级的bin目录生成可执行文件。这样好于肆意目录直接执行顺序。

1.3 项目管理

因为一个概括的计算器程序为例演示如何运用liteIDE开发暨管理项目。如果要管理大多独类型,个人觉得多单门类联合用一个src目录比较便利。使用liteIDE打开$GOPATH目录。在src目录下创造计算器程序项目,目录组织如下:

godev

  |->bin

  |->pkg

 |->src

     |->其它项目…

     |->mycalc

          |->main

              |->main.go

          |->math

              |->add.go

              |->sub.go

          |->math2

              |->mul.go

main.go

package main

import (
    "fmt"
    "mycalc/math"
    "mycalc/math2"
)

func main() {
    fmt.Println("请输入两个整数:")
    var a, b int
    fmt.Scanf("%d %d", &a, &b)
    fmt.Println(a, "+", b, "=", math.Add(a, b))
    fmt.Println(a, "-", b, "=", math.Sub(a, b))
    fmt.Println(a, "*", b, "=", math2.Mul(a, b))

}

add.go代码清单

package math

func Add(a int, b int) int {
    return a + b
}

sub.go代码清单

package math

func Sub(a int, b int) int {
    return a - b
}

mul.go代码清单  

package math2

func Mul(a int, b int) int {
    return a * b
}

瞩目:需要让标使用的Add、Sub和Mul函数首配母大写。