Bootstrap

操作系统原子操作

原子操作

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

;