被c gettimeofdayy害死,又一个线程不安全函数,有没有线程安全代替品

Linux时间函数之gettimeofday()函数之使用方法_Linux编程_Linux公社-Linux系统门户网站
你好,游客
Linux时间函数之gettimeofday()函数之使用方法
来源:Linux社区&
作者:tigerjb
一.gettimeofday()函数的使用方法:
在C语言中可以使用函数gettimeofday()函数来得到时间。它的精度可以达到微妙
2.函数原型:
#include&sys/time.h&
int&gettimeofday(struct& timeval*tv,struct& timezone *tz )
gettimeofday()会把目前的时间用tv 结构体返回,当地时区的信息则放到tz所指的结构中
4.结构体:
struct& timeval{
&&&&&& long& tv_/*秒*/
&&&&&& long& tv_/*微妙*/
2&timezone 结构定义为:
struct& timezone{
&&& &&& int&tz_/*和greenwich 时间差了多少分钟*/
&&& &&& int&tz_/*type of DST correction*/
3&在gettimeofday()函数中tv或者tz都可以为空。如果为空则就不返回其对应的结构体。
4&函数执行成功后返回0,失败后返回-1,错误代码存于errno中。
5.程序实例:
#include&stdio.h&#include&sys/time.h&
#include&unistd.h&
int main()
&&&&&&& struct& timeval&&&&
&&&&&&& struct& timezone&&&
&&& &&& gettimeofday(&tv,&tz);
&&&&&&& printf(“tv_sec:%d\n”,tv.tv_sec);
&&&&&&& printf(“tv_usec:%d\n”,tv.tv_usec);
&&&&&&& printf(“tz_minuteswest:%d\n”,tz.tz_minuteswest);
&&& &&& printf(“tz_dsttime:%d\n”,tz.tz_dsttime);
说明:在使用gettimeofday()函数时,第二个参数一般都为空,因为我们一般都只是为了获得当前时间,而不用获得timezone的数值
相关资讯 & & &
& (03月05日)
& (08/05/:15)
& (05月08日)
& (02月09日)
& (08/04/:48)
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款
匿名 发表于 输出微秒的时候应该用lld或者I64d吧??线程间同步机制(一)
&&&&&&&我们在开发的过程中,经常遇到多个线程访问同一资源的情况,也就是所谓的临界资源。同一个资源对多个线程同时可见,如果均只是读访问,那没毛病,关键是实际生产中读写是一起的。那么问题来了,一个线程在写数据,另外一个线程在读数据,那么读线程读取的很可能是乱码,即使运气好不是乱码,也不是想要的数据,读取的都是脏数据(这里盗用一下数据库术语)。更糟糕的是,多个线程同时在写数据,你想象一下,那将是多么混乱,数据将是一锅粥。说到这里,那么线程间同步的方式有哪些呢?互斥量(Mutex)、条件变量(Condition)、时间(Event)、临界区(CriticalSection)、信号量(Semphore)等等,这里博主只是列举出来一些常见的方法。
&&&&&&&本篇博文我们将一起探讨条件变量(condition),condition统称和mutex一起使用,避免多个线程同时访问condition,进而出现混乱。首先,我们一起来认识几个常用的API吧。
int& pthread_cond_init(pthread_cond_t & *cond, & pthread_condattr_t& *cond_attr);
int& pthread_cond_destroy(pthread_cond_t & *cond);
&&&&& 条件变量和互斥锁一样,都有静态动态两种创建方式,静态方式使用PTHREAD_COND_INITIALIZER常量,如下: & &
pthread_cond_t& cond=PTHREAD_COND_INITIALIZER & &
&&&&&& 动态方式调用pthread_cond_init()函数尽管POSIX标准中为条件变量定义了属性,但在LinuxThreads中没有实现,因此cond_attr值通常为NULL,且被忽略。注销一个条件变量需要调用pthread_cond_destroy(),只有在没有线程在该条件变量上等待的时候才能注销这个条件变量,否则返回EBUSY。因为Linux实现的条件变量没有分配什么资源,所以注销动作只包括检查是否有等待线程。
int& pthread_cond_wait(pthread_cond_t & *cond, & pthread_mutex_t& *mutex);
int& pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t&*mutex, const & struct timespec *abstime);
&&&&&& pthread_cond_wait总和一个互斥锁结合使用。在调用pthread_cond_wait前要先获取锁。pthread_cond_wait函数执行时先自动释放指定的锁(让其他线程可以获得锁,进而可以是袭击获得条件变量,避免死锁),然后等待条件变量的变化(由pthread_cond_signal和pthread_cond_broadcast函数唤醒,即获得条件变量)。在函数调用返回之前,自动将指定的互斥量重新锁住(在没有获得锁之前函数阻塞)。pthread_cond_timedwait函数和pthread_cond_wait类似,pthread_cond_wait在获得条件变量之前会一直阻塞在那里,即永久等待。然而,pthread_cond_timedwait则灵活一点,允许设置等待时间,等待时间过后还没有获得条件变量,函数将不再等待。当然,最后的mutex还是需要等待的,获得mutex后函数立即返回,返回错误码ETIMEDOUT。
intpthread_cond_signal(pthread_cond_t * cond);
pthread_cond_broadcast(pthread_cond_t* cond);
&&&&&&& pthread_cond_signal通过条件变量cond发送消息,若多个消息在等待,它只唤醒一个。pthread_cond_broadcast&& 可以唤醒所有。调用pthread_cond_signal后要立刻释放互斥锁,因为pthread_cond_wait的最后一步是要将指定的互斥量重新锁住,如果pthread_cond_signal之后没有释放互斥锁,pthread_cond_wait仍然要阻塞。
&&&&&&&互斥量(也称为互斥锁)出自POSIX线程标准,可以用来同步同一进程中的各个线程。当然如果一个互斥量存放在多个进程共享的某个内存区中,那么还可以通过互斥量来进行进程间的同步。互斥量,从字面上就可以知道是相互排斥的意思,它是最基本的同步工具,用于保护临界区(共享资源),以保证在任何时刻只有一个线程能够访问共享的资源。
int pthread_mutex_destroy(pthread_mutex_t*mutex);
int pthread_mutex_init(pthread_mutex_t*restrict mutex,const pthread_mutexattr_t *restrict attr);
上面两个函数分别由于互斥量的初始化和销毁。如果互斥量是静态分配的,可以通过常量进行初始化:
pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;
&&&&&& 当然也可以通过pthread_mutex_init()进行初始化。对于动态分配的互斥量由于不能直接赋值进行初始化就只能采用这种方式进行初始化,pthread_mutex_init()的第二个参数是互斥量的属性,如果采用默认的属性设置,可以传入NULL。当不在需要使用互斥量时,需要调用pthread_mutex_destroy()销毁互斥量所占用的资源。
&&&&&&&由于本篇博文主要将条件变量(condition的使用),关于mutex的更详尽学习,博主后期会单独写一篇博文,还要牵扯到mutex的属性设置相关函数。关于mutex的函数就介绍到这里,下面我们看个程序实例吧。相信大家在学习操作系统的时候,都有接触到生产者消费者模型、邮箱模型吧。博主这里写了一个测试程序,就是典型的生产者消费者模型。好了,不多说了,直接上代码吧。
&*使用pthread_cond_t和pthread_mutex_t实现一个多线程下的生产者消费者模型
#include &stdio.h&
#include &stdlib.h&
#include &string.h&
#include &pthread.h&
#include &unistd.h&
#include &queue&
#include &sys/time.h& //
#include &signal.h&
#include &errno.h&
#define PROCEDURE 50//生成线程数
#define CONSUMER 30//消费线程数
//打印指定错误号出错信息
#define handle_error_no(no, msg)\
&&&do {errno = perror(msg); exit(EXIT_FAILURE);}while(0)
//打印错误信息
#define handle_error(msg)\
&&&do {perror(msg); exit(EXIT_FAILURE);}while(0);
//释放mutex锁,并退出线程
//将退出信息通过pthread_exit函数传递给主线程(主线程使用pthread_join的第二个参数接收)
#define thread_exit_id(msg, id, mutex)\
&&&do {char *buf=(char*)malloc(256);sprintf(buf, "%d号%s退出\n",id, msg);pthread_mutex_unlock(&mutex);pthread_exit(buf);}while(0)
//退出线程
#define thread_pro_exit(msg, id)\
&&&do {char *buf=(char*)malloc(256);sprintf(buf, "%d号%s退出\n",id, msg);pthread_exit(buf);}while(0)
pthread_cond_&&& //定义条件变量
pthread_mutex_& //定义mutex(使访问产品队列和修改产品编号操作时原子的)
pthread_mutex_t mutex_//控制开关锁(此锁在同一时间只有两个线程在争用,因为此锁只存在于生产线程的mutex锁内)
bool shift =&&&&& //生产按钮,初始状态为开始状态
//产品结构体
typedef struct produce
&&&int pro_//生产产品号
}produce_t;
std::queue&produce_t& pro_&& //已生产产品队列
int pro_num = 0;&&&&&&& //生产的产品号(从1开始编号)
//中断信号(【ctrl+c】)处理函数
//使生产线程结束生产
void inthandler(int signum)
&&&//加锁操作生产开关
&&&pthread_mutex_lock(&mutex_shift);
&&&shift =//将生产开关关闭
&&&//fprintf(stdout, "stop now!\n");
&&&pthread_mutex_unlock(&mutex_shift);
//生产线程回调函数
void * procedure(void *arg)
&&&int id = *(int *)//接收线程参数
&&&free(arg);//释放参数资源(在主线程中申请的堆上空间)
&&&produce_//存放待生产产品
&&&while (1)
&&&&&&&pthread_mutex_lock(&mutex);//加锁
&&&&&&&//访问生产开关前先加锁
&&&&&&&//当用户发出中断信号,此时只有信号处理函数和当前线程在争用此锁
&&&&&&&pthread_mutex_lock(&mutex_shift);
&&&&&&&if (!shift)
&&&&&&&&&&&pthread_mutex_unlock(&mutex_shift);//退出前先释放锁
&&&&&&&&&&&
&&&&&&&pthread_mutex_unlock(&mutex_shift);
&&&&&&&++pro_//产品号加1
&&&&&&&fprintf(stdout, "%d生产线程开始生产第%d号产品\n", id, pro_num);
&&&&&&&usleep(10);//等待10微妙
&&&&&&&produces.pro_num = pro_
&&&&&&&fprintf(stdout, "%d生产线程结束生产第%d号产品\n", id, pro_num);
&&&&&&&pro_queue.push(produces);//将生产的产品加入已生产产品队列
&&&&&&&//pthread_cond_signal(&cond);//随机唤醒一个等待线程
&&&&&&&pthread_cond_broadcast(&cond);//唤醒所用等待线程
&&&&&&&pthread_mutex_unlock(&mutex);//解锁
&&&&&&&sched_yield();//让出CPU资源,防止此线程一直占用资源
&&&//退出线程,在退出前先释放mutex锁资源
&&&thread_exit_id("生产线程", id, mutex);
//消费线程回调函数
void * consumer(void *arg)
&&&int id = *(int *)//接收线程参数
&&&free(arg);//是否参数资源(在主线程中申请的堆上空间)
&&&produce_//存放贷消费产品
&&&str//设置超时时间用
&&&st//存放当前系统时间用
&&&while (1)
&&&&&&&pthread_mutex_lock(&mutex);//加锁
&&&&&&&//当没有产品时,等待
&&&&&&&if (pro_queue.empty())
&&&&&&&&&&&fprintf(stdout, "%d号消费线程等待消费产品开始\n", id);
&&&&&&&&&&&//等待生产线程的条件
&&&&&&&&&&&//调用该函数是,首先释放锁,在函数调用结束时加锁,使恢复到加锁状态
&&&&&&&&&&&//pthread_cond_wait(&cond, &mutex);
&&&&&&&&&&&gettimeofday(&nowtime, NULL);
&&&&&&&&&&&outtime.tv_sec = nowtime.tv_sec + 1;
&&&&&&&&&&&outtime.tv_nsec = nowtime.tv_usec * 1000;
&&&&&&&&&&&int ret = pthread_cond_timedwait(&cond, &mutex, &outtime);
&&&&&&&&&&&if (ETIMEDOUT == ret) thread_exit_id("消费线程",id, mutex);
&&&&&&&&&&&fprintf(stdout, "%d号消费线程等待消费产品结束\n", id);
&&&&&&&produces = pro_queue.front();//从已生产产品队列中取出队头产品
&&&&&&&fprintf(stdout, "%d号消费线程消费产品%d开始\n", id, produces.pro_num);
&&&&&&&usleep(10);//休眠10微妙&&&&&&&
&&&&&&&fprintf(stdout, "%d号消费线程消费产品%d结束\n", id, produces.pro_num);
&&&&&&&pro_queue.pop();//从队列中删除该产品
&&&&&&&pthread_mutex_unlock(&mutex);//释放锁
&&&&&&&sched_yield();//让出CPU资源&&&&&&&
int main()
&&&pthread_t tid[PROCEDURE+CONSUMER];//定义线程id数组
&&&int i = 0;//循环变量
&&&pthread_cond_init(&cond, NULL);//初始化条件量
&&&pthread_mutex_init(&mutex, NULL);//初始化mutex
&&&pthread_mutex_init(&mutex_shift, NULL);//初始化mutex
&&&//注册中断信号
&&&if (SIG_ERR == signal(SIGINT, inthandler))handle_error("signal");
&&&//创建生产线程
&&&for (i = 0; i & PROCEDURE; ++i)
&&&&&&&int *arg = (int *)malloc(sizeof(int));//为线程参数申请堆上空间
&&&&&&&if (NULL == arg) handle_error("malloc");
&&&&&&&*arg = i+1;//记录线程号
&&&&&&&int ret = pthread_create(tid+i, NULL, procedure, arg);
&&&&&&&if (0 != ret) handle_error_no(ret, "pthread_creat");
&&&//创建消费线程
&&&for (; i & PROCEDURE+CONSUMER; ++i)
&&&&&&&int *arg = (int *)malloc(sizeof(int));//为线程参数申请堆上空间
&&&&&&&if (NULL == arg) handle_error("malloc");
&&&&&&&*arg = i - PROCEDURE + 1;//记录线程号
&&&&&&&int ret = pthread_create(tid + i, NULL, consumer, arg);
&&&&&&&if (0 != ret) handle_error_no(ret, "pthread_creat");
&&&void *buf = NULL;
&&&//主线程阻塞等待子线程退出
&&&for (i = 0; i & PROCEDURE + CONSUMER; ++i)
&&&&&&&//等待子线程退出,接收pthread_exit传出的参数
&&&&&&&pthread_join(tid[i], &buf);
&&&&&&&fprintf(stdout, "%s", (char*)buf);
&&&&&&&free((char*)buf);//释放堆上空间
&&&&&&&buf = NULL;
&&&pthread_cond_destroy(&cond);//销毁条件变量
&&&pthread_mutex_destroy(&mutex);//销毁mutex
&&&pthread_mutex_destroy(&mutex_shift);//销毁mutex
程序截图:
&&&&&& 程序运行的比较快,这里博主只截取了部分运行结果。在上述程序中,有用到前面讲到过得信号,作为最后退出的切入点。博主在程序中添加了很详尽的注释,相信大家已经看明白了,恭喜你又获得了一项新技能。由于实例比较简单,注释也是相当的详尽,博主就不再对程序进行赘述了,小伙伴们,赶紧狂敲代码测试吧。
“Dr信用牛牛”让你远离信用污点
国内首家信用健康管理平台免费为你提供信用修复方案当我们在谈论XX是否线程安全时,我们在谈论什么? - 知乎176被浏览8072分享邀请回答365 条评论分享收藏感谢收起您所在位置: &
&nbsp&&nbsp&nbsp&&nbsp
一个很简单的多线程程序主要用于了解临界区的使用.doc146页
本文档一共被下载:
次 ,您可免费全文在线阅读后下载本文档
文档加载中...广告还剩秒
需要金币:100 &&
--(完美WORD文档DOC格式,可在线免费浏览全文和下载)值得下载!
你可能关注的文档:
··········
··········
一个很简单的多线程程序,主要用于了解临界区的使用
#include #include #include
#pragma comment lib,"libcmt.lib"
const int NLOOP
int counter
void doit void* ;
CRITICAL_SECTION
?HANDLE pnt[2];
?InitializeCriticalSection &
HANDLE _beginthread doit,0,NULL ; ?pnt[1]
HANDLE _beginthread doit,0,NULL ;
?WaitForMultipleObjects
2, pnt, TRUE, 1000L ;
?DeleteCriticalSection & ? ?return 0;
void doit void* ?printf "go...\\n" ;
?int i, val
NLOOP; ++i ? ??EnterCriticalSection &
?? ??printf "%d\\n",val+1 ; ?counter
??LeaveCriticalSection & ?
?printf "end...\\n" ;
目录介绍 1 Linux程序设计入门--基础知识? 2 Linux程序设计入门--进程介绍? 3 Linux程序设计入门--文件操作? 4 Linux程序设计入门--时间概念? 5 Linux程序设计入门--信号处理? 6 Linux程序设计入门--消息管理? 7 Linux程序设计入门--线程操作? 84 8 Linux程序设计入门--网络编程? 9 Linux下C开发工具介绍 具体内容 Linux程序设计入门--基础知识
Linux下C语言编程基础知识 前言: 这篇文章介绍在LINUX下进行C语言编程所需要的基础知识.在这篇文章当中,我们将 会学到以下内容: 源程序编译 Makefile的编写 程序库的链接 程序的调试 头文件和系统求助
int?main int?argc,char?**argv
printf "Hello?Linux\n" ;
要编译这个程序,我们只要在命令行下执行: gcc?-o?hello?hello.c gcc?编译器就会为我们生成一个hello的可执行文件.执行./hello就可以看到程序的输出 结果了.命令行中?gcc表示我们是用gcc来编译我们的源程序,-o?选项表示我们要求编译器给我们输出的可执行文件名为hello?而hello.c是我们的源程序文件. gcc编译器有许多选项,一般来说我们只要知道其中的几个就够了.?-o选项我们已经
正在加载中,请稍后...新手园地& & & 硬件问题Linux系统管理Linux网络问题Linux环境编程Linux桌面系统国产LinuxBSD& & & BSD文档中心AIX& & & 新手入门& & & AIX文档中心& & & 资源下载& & & Power高级应用& & & IBM存储AS400Solaris& & & Solaris文档中心HP-UX& & & HP文档中心SCO UNIX& & & SCO文档中心互操作专区IRIXTru64 UNIXMac OS X门户网站运维集群和高可用服务器应用监控和防护虚拟化技术架构设计行业应用和管理服务器及硬件技术& & & 服务器资源下载云计算& & & 云计算文档中心& & & 云计算业界& & & 云计算资源下载存储备份& & & 存储文档中心& & & 存储业界& & & 存储资源下载& & & Symantec技术交流区安全技术网络技术& & & 网络技术文档中心C/C++& & & GUI编程& & & Functional编程内核源码& & & 内核问题移动开发& & & 移动开发技术资料ShellPerlJava& & & Java文档中心PHP& & & php文档中心Python& & & Python文档中心RubyCPU与编译器嵌入式开发驱动开发Web开发VoIP开发技术MySQL& & & MySQL文档中心SybaseOraclePostgreSQLDB2Informix数据仓库与数据挖掘NoSQL技术IT业界新闻与评论IT职业生涯& & & 猎头招聘IT图书与评论& & & CU技术图书大系& & & Linux书友会二手交易下载共享Linux文档专区IT培训与认证& & & 培训交流& & & 认证培训清茶斋投资理财运动地带快乐数码摄影& & & 摄影器材& & & 摄影比赛专区IT爱车族旅游天下站务交流版主会议室博客SNS站务交流区CU活动专区& & & Power活动专区& & & 拍卖交流区频道交流区
稍有积蓄, 积分 466, 距离下一级还需 34 积分
论坛徽章:0
有得想法绕过去,不知道 time安全不,多线程陷阱太多了
小小吐槽一下~
&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp
腰缠万贯, 积分 9865, 距离下一级还需 135 积分
论坛徽章:229
没有说gettimeofday不是线程安全呀,你怎么用的?
白手起家, 积分 194, 距离下一级还需 6 积分
论坛徽章:0
gettimeofday_r
富足长乐, 积分 5817, 距离下一级还需 2183 积分
论坛徽章:0
应该是线程安全的吧
家境小康, 积分 1292, 距离下一级还需 708 积分
论坛徽章:0
& &透漏下嘛~
第一次听说这个不是线程安全的。。
家境小康, 积分 1935, 距离下一级还需 65 积分
论坛徽章:0
牛人啊,能把一个系统调用变成线程不安全的。
稍有积蓄, 积分 466, 距离下一级还需 34 积分
论坛徽章:0
以为没有人回复呢~
我开了50个线程在 centos上循环跑,偶尔会出现得到的tv_sec 大4500多秒。
于是我使用 time(0)来代替,也会出现这样的情况
& & int ret = gettimeofday(&now, NULL);
& & time_t s = ::time(0);
& & assert(ret == 0);
& & assert (now.tv_sec &= s );
assert 失败,结果会大 4500s。
google 关键词“gettimeofday线程安全”,有一篇
《mktime,localtime_r,gettimeofday是线程安全的吗?》
google “gettimeofday thread-safe”,这篇比较靠前,也有人引用
“The problem, according to POSIX documentation, is that time(), and
& therefore gettimeofday(), keeps some static data that is overwritten by
& each call to the function”
稍有积蓄, 积分 466, 距离下一级还需 34 积分
论坛徽章:0
系统调用gettimeofday 是线程安全,这个是c库里的函数啊,虽然没有看c库源码,但是我确实试出来了不一致
腰缠万贯, 积分 9865, 距离下一级还需 135 积分
论坛徽章:229
以为没有人回复呢~
我开了50个线程在 centos上循环跑,偶尔会出现得到的tv_sec 大4500多秒。
于是我使 ...
ydfgic 发表于
& & 这个是Linux在多核机器上的bug,有补丁的
稍有积蓄, 积分 466, 距离下一级还需 34 积分
论坛徽章:0
多谢,我想也是,不会有人丢那里不管的

我要回帖

更多关于 gettimeofday线程安全 的文章

 

随机推荐