欢迎来到皮皮网网首页

【javaweb方立勋源码】【全面net论坛源码】【mybatis源码解析书籍】mktime的源码_mktime函数源代码

来源:phplinux面板源码 时间:2024-11-25 22:48:43

1.js到底如何将一堆数组通过post的源代码方法发送给php
2.python基础教程 10-11例子如何执行
3.可以在多线程环境中使用mktime和localtime_r吗?

mktime的源码_mktime函数源代码

js到底如何将一堆数组通过post的方法发送给php

       准备数据库

       本例我们使用Mysql数据库,创建一张user表,数源表结构如下:

       CREATE TABLE `user` (

       `id` int() NOT NULL auto_increment,源代码

       `username` varchar() NOT NULL COMMENT '用户名',

       `password` varchar() NOT NULL COMMENT '密码',

       `login_time` int() default NULL COMMENT '登录时间',

       `login_ip` varchar() default NULL COMMENT '登录IP',

       `login_counts` int() NOT NULL default '0' COMMENT '登录次数',

       PRIMARY KEY  (`id`)

       ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

       然后往user表中插入一条用户信息数据:

       INSERT INTO `user` (`id`, `username`, `password`, `login_time`, `login_ip`, `login_counts`)

       VALUES(1, 'demo', 'fece2a7fbac8fafaed7cae', '', '', 0);

       index.php

       用户在输入用户名和密码后,提示用户登录成功,数源并显示相关登录信息,源代码如果点击“退出”,数源javaweb方立勋源码则退出到用户登录界面。源代码

       进入index.php,数源如果用户已登录则显示登录信息,源代码如果未登录则显示登录框要求用户登录。数源

       <div id="login">

       <h3>用户登录</h3>

       <?源代码php

       if(isset($_SESSION['user'])){  ?>

       <div id="result">

       <p><strong><?php echo $_SESSION['user'];?></strong>,恭喜您登录成功!数源</p>

       <p>您这是源代码第<span><?php echo $_SESSION['login_counts'];?></span>次登录本站。</p>

       <p>上次登陆本站的数源时间是:<span><?php echo date('Y-m-d H:i:s',$_SESSION['login_time']);?></span></p><p><a href='#' id='logout'>退出</a></p>

       </div>

       <?php }else{ ?>

       <div id="login_form">

       <p><label>用户名:</label> <input type="text" class="input" name="user" id="user" /></p>

       <p><label>密 码:</label> <input type="password" class="input" name="pass" id="pass" /></p>

       <div class="sub">

       <input type="submit" class="btn" value="登 录" />

       </div>

       </div>

       <?php }?></div>

       注意在index.php文件头应该加上语句:session_start; 同时在head部分引入jquery库,以及包含global.js,源代码您还可以为登录框写个漂亮的CSS样式,当然本例已经略微写了个简单的样式,请查看源码。

       <script type="text/javascript" src="js/jquery.js"></script><script type="text/javascript" src="js/global.js"></script>

       global.js

       global.js文件包括了将要实现的jquery代码。首先要做的就是让输入框获得焦点,像百度和google那样一打开,鼠标光标就在输入框内。使用代码如下:

       $(function(){

       $("#user").focus();

       });

       接着要做的就是,当输入框获得和失去焦点时,分别呈现不同的全面net论坛源码样式,比如本例中使用不同的边框颜色,代码如下:

       $("input:text,textarea,input:password").focus(function() {

       $(this).addClass("cur_select");

       });

       $("input:text,textarea,input:password").blur(function() {

       $(this).removeClass("cur_select");

       });

       用户登录:用户点击登录按钮后,首先要验证用户的输入不能为空,然后向后台login.php发送一个Ajax请求。当后台验证登录成功后,返回登录用户信息:如用户登录次数和上次登录时间等;如果登录失败,则返回登录失败信息。

       $(".btn").live('click',function(){ var user = $("#user").val(); var pass = $("#pass").val(); if(user==""){

       $('<div id="msg" />').html("用户名不能为空!").appendTo('.sub').fadeOut();

       $("#user").focus(); return false;

       } if(pass==""){

       $('<div id="msg" />').html("密码不能为空!").appendTo('.sub').fadeOut();

       $("#pass").focus(); return false;

       }

       $.ajax({ type: "POST", url: "login.php?action=login", dataType: "json", data: { "user":user,"pass":pass}, beforeSend: function(){

       $('<div id="msg" />').addClass("loading").html("正在登录...").css("color","#")

       .appendTo('.sub');

       }, success: function(json){ if(json.success==1){

       $("#login_form").remove(); var div = "<div id='result'><p><strong>"+json.user+"</strong>,恭喜您登录成功!</p>

       <p>您这是第<span>"+json.login_counts+"</span>次登录本站。</p>

       <p>上次登录本站的时间是:<span>"+json.login_time+"</span></p><p>

       <a href='#' id='logout'>退出</a></p></div>";

       $("#login").append(div);

       }else{

       $("#msg").remove();

       $('<div id="errmsg" />').html(json.msg).css("color","#").appendTo('.sub')

       .fadeOut(); return false;

       }

       }

       });

       });

       我在进行Ajax请求时,数据传输格式使用的是json,返回的数据也是json数据,使用JS将json数据解析,得到登录后的用户信息,然后通过append追加到#login元素下,完成登录操作。

       用户退出:当点击“退出”时,向login.php发送一个Ajax请求,后台注销所有Session,页面重新回到登录界面。

       $("#logout").live('click',mybatis源码解析书籍function(){

       $.post("login.php?action=logout",function(msg){ if(msg==1){

       $("#result").remove(); var div = "<div id='login_form'><p><label>用户名:</label>

       <input type='text' class='input' name='user' id='user' /></p>

       <p><label>密 码:</label> <input type='password' class='input' name='pass'

       id='pass' /></p>

       <div class='sub'><input type='submit' class='btn' value='登 录' /></div>

       </div>";

       $("#login").append(div);

       }

       });

       });

       login.php

       根据前台提交的请求,登录时,获取用户输入的用户名和密码,并与数据库中对应的用户名和密码进行比对,如果比对成功,则将新的更新该用户登录信息,并组装json数据传给前台。

       session_start();require_once ('connect.php');

       $action = $_GET['action'];if ($action == 'login') {  //登录

       $user = stripslashes(trim($_POST['user']));

       $pass = stripslashes(trim($_POST['pass'])); if (empty ($user)) { echo '用户名不能为空'; exit;

       } if (empty ($pass)) { echo '密码不能为空'; exit;

       }

       $md5pass = md5($pass); //密码使用md5加密

       $query = mysql_query("select * from user where username='$user'");

       $us = is_array($row = mysql_fetch_array($query));

       $ps = $us ? $md5pass == $row['password'] : FALSE; if ($ps) {

       $counts = $row['login_counts'] + 1;

       $_SESSION['user'] = $row['username'];

       $_SESSION['login_time'] = $row['login_time'];

       $_SESSION['login_counts'] = $counts;

       $ip = get_client_ip(); //获取登录IP

       $logintime = mktime();

       $rs = mysql_query("update user set login_time='$logintime',login_ip='$ip',

       login_counts='$counts'"); if ($rs) {

       $arr['success'] = 1;

       $arr['msg'] = '登录成功!';

       $arr['user'] = $_SESSION['user'];

       $arr['login_time'] = date('Y-m-d H:i:s',$_SESSION['login_time']);

       $arr['login_counts'] = $_SESSION['login_counts'];

       } else {

       $arr['success'] = 0;

       $arr['msg'] = '登录失败';

       }

       } else {

       $arr['success'] = 0;

       $arr['msg'] = '用户名或密码错误!';

       } echo json_encode($arr); //输出json数据}elseif ($action == 'logout') {  //退出

       unset($_SESSION);

       session_destroy(); echo '1';

       }

       当前台请求退出时,只需注销session就可以,并返回1给前台JS处理。

python基础教程 -例子如何执行

       . 模块相关

       Python的标准安装包包括一组模块,称为标准库(standard library)。

       .1 模块

       .1.1 模块是程序

       # hello.pyprint "Hello, world!"# 保存放在C:\python# 告诉解释器在哪里寻找模块>>> import sys>>> sys.path.append('c:/python')# 这样,解释器除了从默认的目录中寻找之外,还需要从目录c:\python中寻找模块>>> import hello

       Hello, world!

       导入模块多次和导入一次的效果是一样的。如果坚持重新载入模块,可以使用内建的reload函数。

       .1.2 模块用于定义

       在模块中定义函数

       # hello2.pydef hello():

       print "Hello, world# 使用import hello2

       hello2.hello()

       在模块中增加测试代码

       为 “告知” 模块本身是作为程序运行还是导入到其他程序,需要使用__name__变量:

       # hello4.pydef hello():

       print "Hello, world!"def test():

       hello()if __name__ == '__main__': test()

       .1.3 让模块可用

       将模块放置在正确位置

       # 下面命令列出的路径都可以放置,但site-packages目录是最佳选择>>> import sys, pprint>>> pprint.pprint(sys.path)

       告诉编译器去哪里找

       除了编辑sys.path外,更通用的方法是设置环境变量PYTHONPATH

       .1.4 包

       当模块存储在文件中时(扩展名.py),包就是模块所在的目录。为了让Python将其作为包对待,hibernate4.3.11源码它必须包含一个命名为__init__py的文件(模块)。如果将它作为普通模块导入的话,文件的内容就是包的内容。

       vim constants/__init__.py

       PI=3.# 别的地方引用import constantsprint constants.PI

       .2 探究模块

       .2.1 模块中有什么

       使用dir

       查看模块包含的内容,它会将对象(以及模块的所有函数、类、变量等)的所有特性列出。

       # 导入模块

       import copy# 列表推导式是个包含dir(copy)中所有不以下划线开头的名字的列表。

       [n for n in dir(copy)] if not n.startwith('_')]

       __all__变量

       这个变量包含一个列表,该列表与上一节的列表类似。

       copy.__all__1

       它定义了模块的共有接口,在编写模块的时候,像设置__all__这样的技术是相当有用的。

       __all__ = ["Error", "copy", "deepcopy"]1

       .2.2 用help获取帮助

       使用help函数,获得帮助文本。

       help(copy.copy)1

       .2.3 文档

       参考

       .2.4 使用源代码

       方案一:检查sys.path,然后自己找。

       方案二:检查模块的__file__属性

       .3 标准库

       .3.1 sys

       sys这个模块能够访问与Python解释器联系紧密的变量和函数。部分重要函数和变量如下:

       函数/变量

       描述

       argv    命令行参数,包括传递到Python解释器的参数,脚本名称    

       exit([arg])    退出当前的程序,可选参数为给定的返回值或错误信息    

       modules    映射模块名字到载入模块的字典    

       path    查找模块所在目录的目录名列表    

       platform    类似sunos5或win的平台标识符    

       stdin    标准输入流——一个类文件(file-like)对象    

       stdout    标准输出流    

       stderr    标准错误流    

       .3.2 os

       os模块提供了访问多个操作系统服务的功能。下表列出一些最有用的函数和变量。另外,370safe源码os和它的子模块os.path还包含一些用于检查、构造、删除目录和文件的函数,以及一些处理路径的函数(例如,os.path.split和os.path.join让你在大部分情况下都可以忽略os.pathsep)。

       函数/变量

       描述

       environ    对环境变量进行映射    

       system(command)    在子shell中执行操作系统命令    

       sep    路径中的分隔符    

       pathsep    分隔路径的分隔符    

       linesep    行分隔符    

       urandom(n)    返回n个字节的加密强随机数据    

       .3.3 fileinput

       fileinput模块能够轻松地遍历文本文件的所有行。

       函数/变量

       描述

       input([files[, inplace[, backup]]])    便于遍历多个输入流中的行    

       filename()    返回当前文件的名称    

       lineno()    返回当前(累计)的行数    

       filelineno()    返回当前文件的行数    

       isfirstline()    检查当前行是否是文件的第一行    

       isstdin()    检查最后一行是否来自sys.stdin    

       nextfile()    关闭当前文件,移动到下一个文件    

       close()    关闭序列    

       为Python脚本添加行号

       # numberlines.pyimport fileinputfor line in fileinput.input(inplcae=True)  line = line.rstrip()  num = fileinput.lineno()

       print '%-s # %2i' % (line, num)

       .3.4 集合、堆和双端队列

       集合

       Set类位于sets模块中。非重复、无序的序列。

       堆

       堆(heap)是优先队列的一种。使用优先队列能够以任意顺序增加对象,并且能在任何时间找到最小的元素,也就是说它比用于列表的min方法要有效率得多。下面是heapq模块中重要的函数:

       函数

       描述

       heappush(heap, x)    将x入堆    

       heappop(heap)    将堆中最小的元素弹出    

       heapify(heap)    将heap属性强制应用到任意一个列表,将其转换为合法的堆    

       heapreplace(heap, x)    将堆中最小的元素弹出,同时将x入堆    

       nlargest(n, iter)    返回iter中第n大的元素    

       nsmallest(n, iter)    返回iter中第n小的元素    

       元素虽然不是严格排序的,但是也有规则:i位置处的元素总比2*i以及2*i+1位置处的元素小。这是底层堆算法的基础,而这个特性称为堆属性(heap property)。

       双端队列(以及其他集合类型)

       双端队列(Double-ended queue)在需要按照元素增加的顺序来移除元素时非常有用。它能够有效地在开头增加和弹出元素,这是在列表中无法实现的,除此之外,使用双端队列的好处还有:能够有效地旋转(rotate)元素。deque类型包含在collections模块。

       .3.5 time

       time模块所包含的函数能够实现以下功能:获得当前时间、操作时间和日期、从字符串读取时间以及格式化时间为字符串。日期可以用实数或者包含有9个整数的元组。元组意义如下:

       索引

       字段

       值

       0    年    比如等    

       1    月    范围1~    

       2    日    范围1~    

       3    时    范围0~    

       4    分    范围0~    

       5    秒    范围0~(应付闰秒和双闰秒)    

       6    周    当周一为0时,范围0~6    

       7    儒历日    范围1~    

       8    夏令日    0、1、-1    

       time的重要函数:

       函数

       描述

       asctime([tuple])    将时间元组转换为字符串    

       localtime([secs])    将秒数转换为日期元组,以本地时间为准    

       mktime(tuple)    将时间元组转换为本地时间    

       sleep(secs)    休眠secs秒    

       strptime(string[, format])    将字符串解析为时间元组    

       time()    当前时间(新纪元开始后的秒数,以UTC为准)    

       .3.6 random

       random模块包括返回随机数的函数,可以用于模拟或者用于任何产出随机输出的程序。

       如果需要真的随机数,应该使用os模块的urandom函数。random模块内的SystemRandom类也是基于同样功能。

       函数

       描述

       random()    返回0 <= n < 1之间的随机实数n,其中0 < n <=1    

       getrandbits(n)    以长整型形式返回n个随机位    

       uniform(a, b)    返回随机实数n,其中 a <= n < b    

       randrange([start], stop, [step])    返回range(start, stop, step)中的随机数    

       choice(seq)    从序列seq中返回随机元素    

       shuffle(seq[, random])    原地指定序列seq    

       sample(seq, n)    从序列seq中选择n个随机且独立的元素    

       示例一:

       from random import *from time import

*

       date1 = (, 1, 1, 0, 0, 0, -1, -1, -1)

       time1 = mktime(date1)

       date2 = (, 1, 1, 0, 0, 0, -1, -1, -1)

       time2 = mktime(date2)

       random_time = uniform(time1, time2)print asctime(localtime(random_time))

       .3.7 shelve

       提供一个存储方案。shelve的open函数返回一个Shelf对象,可以用它来存储内容。只需要把它当做普通的字典来操作即可,在完成工作之后,调用close方法。

       import shelve

       s = shelve.open('test.dat')

       s['x'] = ['a', 'b', 'c']# 下面代码,d的添加会失败# s['x'].append('d')# s['x']# 正确应该使用如下方法:temp = s['x']

       temp.append('d')

       s['x'] = temp

       .3.8 re

       re模块包含对正则表达式的支持。

       正则表达式

       .号只能匹配一个字符(除换行符外的任何单个字符)。

       \为转义字符

       字符集:使用[]括起来,例如[a-zA-Z0-9],使用^反转字符集

       选择符(|)和子模式():例如'p(ython|erl)'

       可选项(在子模式后面加上问号)和重复子模式:例如r'(pile(pattern[, flags])    根据包含正则表达式的字符串创建模式对象    

       search(pattern, string[, flags])    在字符串中寻找模式    

       match(pattern, string[, flags])    在字符串的开始处匹配模式    

       split(pattern, string[, maxsplit=0])    根据模式的匹配项来分隔字符串    

       findall(pattern, string)    列出字符串中模式的所有匹配项    

       sub(pat, repl, string[, count=0])    将字符串中所有pat的匹配项用repl替换    

       escape(string)    将字符串中所有特殊正则表达式字符转义    

       匹配对象和组

       对于re模块中那些能够对字符串进行模式匹配的函数而言,当能找到匹配项时,返回MatchObject对象。包含了哪个模式匹配了子字符串的哪部分的信息。——这些“部分”叫做组。

       组就是放置在圆括号内的子模式。组的序号取决于它左侧的括号数。组0就是整个模式。

       re匹配对象的一些方法:

       方法

       描述

       group([group1, …])    获取给定子模式(组)的匹配项    

       start([group])    返回给定组的匹配项的开始位置    

       end([group])    返回给定组的匹配项的结束位置(和分片一样,不包括组的结束位置)    

       span([group])    返回一个组的开始和结束位置    

       作为替换的组号和函数

       示例:假设要把'*something*'用<em>something</em>替换掉:

emphasis_pattern = r'\*([^\*]+)\*'# 或者用VERBOSE标志加注释,它允许在模式中添加空白。emphasis_pattern = re.compile(r'''

                \*      # 开始的强调标签

                (       # 组开始

                [^\*]+  # 除了星号的所有字符

                )       # 组结束

                \*      # 结束的强调标签

                ''', re.VERBOSE)

       re.sub(emphasis_pattern, r'<em>\1</em>', 'Hello, *world*!')# 结果'Hello, <em>world</em>!'

       找出Email的发信人

# 示例一# 匹配内容:From: Foo Fie <foo@bar.baz># find_sender.pyimport fileinput, re

       pat = re.compile('From: (.*) <.*?>$')for line in fileinput.input():

        m = pat.match(line)  if m: print m.group(1)# 执行$ python find_sender.py message.eml# 示例二# 列出所有Email地址import fileinput, re

       pat = re.compile(r'[a-z\-\.]+@[a-z\-\.]+', re.IGNORECASE)

       addresses = set()for line in fileinput.input():  for address in pat.findall(line):

          addresses.add(address)for address in sorted(addresses):  print address

       模板系统示例

       模板是一种通过放入具体值从而得到某种已完成文本的文件。

       示例:把所有'[somethings]'(字段)的匹配项替换为通用Python表达式计算出来的something结果

'The sum of 7 and 9 is [7 + 9].'

       应该翻译成'The sum of 7 and 9 is .'

       同时,可以在字段内进行赋值

       '[name="Mr. Gumby"]Hello, [name]'

       应该翻译成'Hello, Mr. Gumby'

       代码如下

# templates.py#!/usr/bin/python# -*- coding: utf-8 -*-import fileinput, re# 匹配中括号里的字段field_pat = re.compile(r'\[(.+?)\]')# 我们将变量收集到这里scope = { }# 用于re.sub中def replacement(match):

        code = match.group(1)  try:    # 如果字段可以求值,返回它:

          return str(eval(code, scope))  except SyntaxError:    # 否则执行相同作用域内的赋值语句......

          exec code in scope    # ......返回空字符串

          return ''# 将所有文本以一个字符串的形式获取lines = []for line in fileinput.input():

        lines.append(line)

       text = ''.join(lines)# 将field模式的所有匹配项都替换掉print field_pat.sub(replacement, text)

       .3.9 其他标准模块

       functools:能够通过部分参数来使用某个函数(部分求值),稍后再为剩下的参数提供数值。

       difflib:可以计算两个序列的相似程度。还能从一些序列中(可供选择的序列列表)找出和提供的原始序列“最像”的那个。可以用于创建简单的搜索程序。

       hashlib:可以通过字符串计算小“签名”。

       csv:处理CSV文件

       timeit、profile和trace:timeit(以及它的命令行脚本)是衡量代码片段运行时间的工具。它有很多神秘的功能,应该用它代替time模块进行性能测试。profile模块(和伴随模块pstats)可用于代码片段效率的全面分析。trace模块(和程序)可以提供总的分析(覆盖率),在写测试代码时很有用。

       datetime:支持特殊的日期和时间对象,比time的接口更直观。

       itertools:有很多工具用来创建和联合迭代器(或者其他可迭代对象),还包括实现以下功能的函数:将可迭代的对象链接起来、创建返回无限连续整数的迭代器(和range类似,但没有上限),从而通过重复访问可迭代对象进行循环等等。

       logging:输出日志文件。

       getopt和optparse:在UNIX中,命令行程序经常使用不同的选项或开关运行。getopt为解决这个问题的。optparse则更新、更强大。

       cmd:可以编写命令行解释器。可以自定义命令。

       .4 新函数

       函数

       描述

       dir(obj)    返回按字母顺序排序的属性名称列表    

       help([obj])    

       reload(module)    

       . 文件

       .1 打开文件

       open函数用来打开文件,语法如下:

open(name[, mode[, buffering]])1

       .1.1 文件模式

       默认只读打开。

       值

       描述

       ‘r’    读模式    

       ‘w’    写模式    

       ‘a’    追加模式    

       ‘b’    二进制模式(可添加到其他模式中使用)    

       ‘+’    读/写模式(可添加到其他模式中使用)    

       .1.2 缓存

       open函数的第三个参数(可选)控制文件的缓冲。有缓冲时,只有使用flush或close时才会更新硬盘上的数据。

       值

       描述

       0或False    无缓冲    

       1或True    有缓冲    

       大于1的数字    缓冲区大小(字节)    

       -1或负数    默认的缓冲区大小    

       .2 基本文件方法

       .2.1 读和写

>>> f = open('somefile.txt', 'w')>>> f.write('Hello, ')>>> f.write('World!')>>> f.close()>>> f = open('somefile.txt', 'r')>>> f.read(4)  # 读取的字符数(字节)'Hell'>>> f.read()'o, World!'

       .2.2 管式输出

# somescript.pyimport systext = sys.stdin.read()words = text.split()

       wordcount = len(words)

可以在多线程环境中使用mktime和localtime_r吗?

       localtime和mktime是用于在时间分量和时间秒数之间转换的标准c函数.

       在glibc文档描述中,localtime的实现使用内部静态缓存来保存结果,因此这是一个API,不适用于多线程环境. glibc提供了线程安全的localtime_r版本. mktime没有这个问题.

       因此,根据glibc文档,在多线程环境中使用localtime_r和mktime是安全的localtime 线程安全。

       mktime和localtime_r的实现都考虑了时区的转换,并且时区的计算应使用全局变量tzname / timezone / daylight. 这本质上是线程不安全的.

       请参阅glibc-2.3.2的源代码(下面的源代码位置均相对于源目录)

       --------- time / localtime.c和time / tzset.c

       在localtime_r中,调用tzset_internal来设置时区. 输入参数始终为0,因此从理论上讲,只要第一次结束,就无需初始化. 请参阅下面的代码.

       但是,由于在多线程环境中引入了静态变量is_initialized,因此该实现代码存在问题. 无法保证并发执行环境的正确性.

       ----(时间/ tzset.c)-------

       / *解释TZ变量. * /

       静态无效

       内部功能

       tzset_internal(始终)

       int始终;

       {

       static int is_initialized;

       注册const char * tz;

       寄存器size_t l;

       char * tzbuf;

       unsigned short int hh,mmlocaltime 线程安全,ss;

       无符号短整数规则;

       如果(始终被is_initialized &&!)

       返回;

       is_initialized = 1;

       .

       }

       但是mktime不是这样的

       ----(时间/ mktime.c)-------

       / *将* TP转换为time_t值. * /

       time_t

       mktime(tp)

       struct tm * tp;

       {

       #ifdef _LIBC

       / * POSIX.1 8.1.1要求,每当调用mktime()时。

       外部变量`tzname'中包含的

       时区名称

       设置

       就像调用tzset()函数一样. * /

       __ tzset();

       #endif

       返回__mktime_internal(tp,my_mktime_localtime_r和localtime_offset);

       }

       由于定义了_LIBC,每次都会调用tzset,因此tzset的代码是这样的

       ----(时间/ tzset.c)-------

       无效

       __ tzset(无效)

       {

       __ libc_lock_lock(tzset_lock);

       tzset_internal(1);

       如果(!____ use_tzfile)

       {

       / *设置`tzname'. * /

       __ tzname [0] =(char *)tz_rules [0] .name;

       __ tzname [1] =(char *)tz_rules [1] .name;

       }

       __ libc_lock_unlock(tzset_lock);

       }

       每次都会调用tzset_internal,并且每次都将重写时区信息.

       应注意,前面的宏__libc_lock_lock在sysdeps / generic / bits / libc-lock.h中定义为:

       #define __libc_lock_lock(名称)

       是无操作操作,因此它不能用作同步线程.

       因此,您可以看到上述glibc代码实现中存在两个问题:

       1. tzset_internal is_initialized中使用的静态变量

       (这可以通过在程序中定义一个无用的全局变量并程开始工作之前在其初始化中调用mktime来克服)

       2. mktime必须每次都重写全局变量tzname / timezone / daylight

       (这个问题基本上是没有办法解决的)

       因此mktime和localtime_r不适合多线程应用程序.

       有两种解决方案:

       1. 自己实现mktime和localtime_r,但是时区的计算很麻烦. 当然,您不能使用时区信息,也不能使用固定时区,例如北京时区.

       2. 使用pthread的互斥锁来锁定mktime和localtime_r,但是以这种方式使用pthread库,可移植性不够好.