操作系统原子操作
原子操作
所谓的原子操作就是不可被拆分的操作,对于多线程对全局变量进行操作时,就再也不用再线程锁了,和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);
}
