原子操作
所谓的原子操作就是不可被拆分的操作,对于多线程对全局变量进行操作时,就再也不用再线程锁了,和pthread_mutex_t保护作用是一样的,也是线程安全的,有些编译器在使用时需要加-march=i686编译参数。
type __sync_fetch_and_add (type *ptr, type value); // + type __sync_fetch_and_sub (type *ptr, type value); // - type __sync_fetch_and_and (type *ptr, type value); // & type __sync_fetch_and_or (type *ptr, type value); // | type __sync_fetch_and_nand (type *ptr, type value); // ~ type __sync_fetch_and_xor (type *ptr, type value); // ^ 功能:以上操作返回的是*ptr的旧值 type __sync_add_and_fetch (type *ptr, type value); // + type __sync_sub_and_fetch (type *ptr, type value); // - type __sync_and_and_fetch (type *ptr, type value); // & type __sync_or_and_fetch (type *ptr, type value); // | type __sync_nand_and_fetch (type *ptr, type value); // ~ type __sync_xor_and_fetch (type *ptr, type value); // ^ 功能:以上操作返回的是*ptr与value计算后的值 type __sync_lock_test_and_set (type *ptr, type value); 功能:把value赋值给*ptr,并返回*ptr的旧值 __sync_lock_release(type *ptr); 功能:将*ptr赋值为0
#include <stdio.h> #include <pthread.h> int num = 0; void* run(void* arg) { for(int i=0; i<100000000; i++) { __sync_fetch_and_add(&num,1); } } int main(int argc,const char* argv[]) { pthread_t pid1,pid2; pthread_create(&pid1,NULL,run,NULL); pthread_create(&pid2,NULL,run,NULL); pthread_join(pid1,NULL); pthread_join(pid2,NULL); printf("%d\n",num); }
原子操作的优点:
1、速度贼快
2、不会产生死锁
原子操作的缺点:
1、该功能并不通用,有些编译器不支持。
2、type只能是整数相关的类型,浮点型和自定义类型无法使用。
练习1:
使用读写锁或互斥锁实现一个线程安全队列。
#include "queue.h" #include <stdlib.h> Node* create_node(TYPE data) { Node* node = malloc(sizeof(Node)); node->data = data; node->next = NULL; return node; } Queue* create_queue(void) { Queue* queue = malloc(sizeof(Queue)); pthread_rwlock_init(&queue->lock,NULL); queue->front = NULL; queue->rear = NULL; return queue; } bool empty_queue(Queue* queue) { pthread_rwlock_rdlock(&queue->lock); bool flag = NULL == queue->front; pthread_rwlock_unlock(&queue->lock); return flag; } void push_queue(Queue* queue,TYPE data) { Node* node = create_node(data); if(empty_queue(queue)) { pthread_rwlock_wrlock(&queue->lock); queue->front = node; queue->rear = node; } else { pthread_rwlock_wrlock(&queue->lock); queue->rear->next = node; queue->rear = node; } pthread_rwlock_unlock(&queue->lock); } bool pop_queue(Queue* queue) { if(empty_queue(queue)) return false; pthread_rwlock_wrlock(&queue->lock); Node* tmp = queue->front; queue->front = tmp->next; pthread_rwlock_unlock(&queue->lock); free(tmp); return true; } TYPE top_queue(Queue* queue) { pthread_rwlock_rdlock(&queue->lock); TYPE data = queue->front->data; pthread_rwlock_unlock(&queue->lock); return data; } void destroy_queue(Queue* queue) { while(!empty_queue(queue)) pop_queue(queue); pthread_rwlock_destroy(&queue->lock); free(queue); } int main(void) { Queue* queue = create_queue(); for(int i=0; i<10; i++) { push_queue(queue,i); printf("push %d\n",i); } while(!empty_queue(queue)) { printf("top %d\n",top_queue(queue)); pop_queue(queue); } }
练习2:
使用原子操作实现一个线程安全的无锁队列。
//queue->rear = (queue->rear+1)%queue->cap; if(queue->rear == queue->cap) { queue->rear = 0; } else { __sync_fetch_and_add(&queue->rear,1); } queue->front = (queue->front+1)%queue->cap; if(queue->front == queue->cap) { queue->front = 0; } else { __sync_fetch_and_add(&queue->front,1); }