Linux下线程同步机制(吐血整理)

您所在的位置:网站首页 操作系统线程和进程的同步机制和通信机制 Linux下线程同步机制(吐血整理)

Linux下线程同步机制(吐血整理)

2023-11-03 12:01| 来源: 网络整理| 查看: 265

线程同步 资源竞争线程同步1. 互斥锁2. 读写锁3. 自旋锁4. 信号量5. 条件变量6. 屏障

资源竞争

当进程中的多个线程,同时读取一块内存数据,与此同时其中一个或多个线程修改了这块内存数据。这样就会导致不可预期的结果

因为线程不安全引起的错误往往非常难发现,因为这种现象是不能稳定复现的。

下面举个例子:

#include #include #include int g = 0; //100000000-200000000 void *pf(void *arg){ int i; for(i=0;i pthread_t ids[2]; int ret1 = pthread_create(&ids[0],NULL,pf,NULL); int ret2 = pthread_create(&ids[1],NULL,pf,NULL); if(ret1 != 0 || ret2 != 0){ printf("pthread_create:%s\n",strerror(ret1!=0?ret1:ret2)); return -1; } int i; for(i=0;i int i; for(i=0;i pthread_t ids[2]; int ret = pthread_mutex_init(&lock,NULL); if(ret != 0){ printf("pthread_mutex_init:%s\n",strerror(ret)); } int ret1 = pthread_create(&ids[0],NULL,pf,NULL); int ret2 = pthread_create(&ids[1],NULL,pf,NULL); if(ret1 != 0 || ret2 != 0){ printf("pthread_create:%s\n",strerror(ret1!=0?ret1:ret2)); return -1; } int i; for(i=0;i time_t tv_sec; // Seconds long tv_nsec; // Nanoseconds [0 - 999999999] }; // 信号量加1 int sem_post (sem_t* sem); // 销毁信号量 int sem_destroy (sem_t* sem); int sval; sem_getvalue (&g_sem, &sval); //获取当前信号量,并存入sval中

范例:

#include #include #include #include int g = 0; sem_t sem; //100000000-200000000 void *pf(void *arg){ int i; for(i=0;i pthread_t ids[2]; int ret = sem_init(&sem,0,1); if(ret != 0){ perror("sem_init"); } int ret1 = pthread_create(&ids[0],NULL,pf,NULL); int ret2 = pthread_create(&ids[1],NULL,pf,NULL); if(ret1 != 0 || ret2 != 0){ printf("pthread_create:%s\n",strerror(ret1!=0?ret1:ret2)); return -1; } int i; for(i=0;i pthread_t tid = pthread_self (); int sval; sem_getvalue (&g_sem, &sval); printf ("%lu线程:等待数据库连接(还剩%d个空闲连接)...\n", tid, sval); sem_wait (&g_sem); sem_getvalue (&g_sem, &sval); printf ("%lu线程:获得数据库连接(还剩%d个空闲连接)!\n", tid, sval); usleep (1000000); sem_post (&g_sem); sem_getvalue (&g_sem, &sval); printf ("%lu线程:释放数据库连接(还剩%d个空闲连接)。\n", tid, sval); return NULL; } int main (void) { size_t i; pthread_t tids[MAX_USERS]; int error; sem_init (&g_sem, 0, MAX_CONNS); for (i = 0; i fprintf (stderr, "pthread_create: %s\n", strerror (error)); return -1; } } for (i = 0; i fprintf (stderr, "pthread_join: %s\n", strerror (error)); return -1; } } sem_destroy (&g_sem); return 0; } 5. 条件变量

生产者消费者模型 生产者:产生数据的线程。 消费者:使用数据的线程。 在这里插入图片描述 通过缓冲区隔离生产者和消费者,与二者直连相比,避免相互等待,提高运行效率。 生产快于消费,缓冲区满,撑死。 消费快于生产,缓冲区空,饿死。

条件变量可以让调用线程在满足特定条件的情况下暂停。

int pthread_cond_init (pthread_cond_t* cond,const pthread_condattr_t* attr); //亦可pthread_cond_t cond = PTHREAD_COND_INITIALIZER; // 使调用线程睡入条件变量cond,同时释放互斥锁mutex 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); struct timespec { time_t tv_sec; // Seconds long tv_nsec; // Nanoseconds [0 - 999999999] }; // 从条件变量cond中唤出一个线程, // 令其重新获得原先的互斥锁 int pthread_cond_signal (pthread_cond_t* cond); 注意:被唤出的线程此刻将从pthread_cond_wait函数中返回, 但如果该线程无法获得原先的锁,则会继续阻塞在加锁上。 // 从条件变量cond中唤出所有线程 int pthread_cond_broadcast (pthread_cond_t* cond); int pthread_cond_destroy (pthread_cond_t* cond);

范例:

#include #include #include #include #include pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t notempty = PTHREAD_COND_INITIALIZER;//不为空的条件 pthread_cond_t notfull = PTHREAD_COND_INITIALIZER;//不为满的条件 #define CAPCITY 20 char stock[CAPCITY]; int size = 0; void show(const char *who,const char *con,char s){ int i; for(i=0;i const char *who = (char*)arg; for(;;){ pthread_mutex_lock(&mutex); //被唤醒之后 需要重新判断仓库是否满了 while(size >= CAPCITY){//仓库满了,不能进行生产 printf("仓库满了,%s线程不能进行生产!\n",who); //释放锁 要等待 仓库不满的信号 pthread_cond_wait(¬full,&mutex);//阻塞释放锁 //被唤醒之后 重新获得锁 printf("有人进行了消费,%s线程可以进行生产了!\n",who); } char prod = 'A'+rand()%26; show(who,"


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3