linux线程同步教程,多线程同步
1.linux使用多線程同步的方法
1)互斥鎖:當線程A鎖定了互斥變量時,線程B再去鎖定時就會被掛起,直到A解鎖。
注意:當線程要不斷的去輪詢檢查某個條件以判斷是否可以操作需同步的數據時,可使用條件變量提高效率。
demo如下:
#include
#include
#include
?
pthread_mutex_t mutex;
?
void *print_msg(void *arg)
{
int i = 0;
pthread_mutex_lock(&mutex); //互斥鎖加鎖
for (i = 0; i < 20; i++)
{
printf(" i = %d\n", i);
usleep(200);
}
pthread_mutex_unlock(&mutex);
?
}
?
int main()
{
pthread_t id1, id2;
pthread_mutex_init(&mutex, NULL);
pthread_create(&id1, NULL, print_msg, NULL);
pthread_create(&id2, NULL, print_msg, NULL);
pthread_join(id1, NULL); //使主線程等待該線程結束后才結束,否則主線程很快結束,該線程沒有機會執行
pthread_join(id2, NULL);
pthread_mutex_destroy(&mutex);
?
return 0;
}
2)信號量:實際是一個整數,只要信號量的value大于0,其他線程就可以sem_wait成功,成功后信號量的value減1。若value值不大于0,則sem_wait使得線程阻塞,直到sem_post釋放后value值加1,但是sem_wait返回之前還是會將此value值減1。
demo如下:
#include
#include
#include
#include
#include
#include
?
void *thread_func(void* msg);
sem_t sem;
sem_t sem_add;
?
#define MSG_SIZE 512
?
int main()
{
int res = -1;
pthread_t thread;
void *thread_result = NULL;
char msg[MSG_SIZE];
?
res = sem_init(&sem, 0, 0);
if (res == -1)
{
printf("sem init failed\n");
exit(-1);
}
?
res = sem_init(&sem_add, 0, 1);
if (res == -1)
{
printf("sem_add init failed\n");
exit(-1);
}
?
res = pthread_create(&thread, NULL, thread_func, msg);
if (res != 0)
{
printf("pthread_create failed\n");
exit(-1);
}
printf("input some text. Enter 'end' to finish...\n");
sem_wait(&sem_add);
while(strcmp("end\n", msg) != 0)
{
if (strncmp(msg, "TEST", 4) == 0)
{
strcpy(msg, "copy_data\n");
sem_post(&sem);
sem_wait(&sem_add);
}
fgets(msg, MSG_SIZE, stdin);
sem_post(&sem); //sem信號量加1,讓子線程開始執行
sem_wait(&sem_add); //sem_add信號量減1,等待子線程處理完成
?
}
?
printf("waiting for thread to finish...\n");
res = pthread_join(thread, &thread_result);
if (res != 0)
{
printf("pthread_join faild\n");
exit(-1);
}
?
printf("thread joined\n");
?
sem_destroy(&sem);
sem_destroy(&sem_add);
exit(0);
?
return 0;
}
?
void* thread_func(void* msg)
{
char *ptr = (char*)msg;
sem_wait(&sem);
while(strcmp("end\n", ptr) != 0)
{
int i = 0;
for (; ptr[i] != '\0'; ++i )
{
if (ptr[i] >= 'a' && ptr[i] <= 'z')
{
ptr[i] -= 'a' - 'A';
}
}
printf("you input %d characters\n", i - 1);
printf("to uppercase: %s\n", ptr);
?
sem_post(&sem_add);
sem_wait(&sem);
}
sem_post(&sem_add);
pthread_exit(NULL);
}
3)條件變量:經常和互斥鎖一起使用,使用時,條件變量被用來阻塞一個線程,當條件不滿足時,線程會解開相應的互斥鎖并等待條件發生變化,一旦其他的某個線程改變了條件變量,它將通知相應的條件變量喚醒一個或多個正被此變量阻塞的線程,這些線程將重新鎖定互斥鎖并重新測試條件是否滿足。
pthread_cont_init()
pthread_cont_destroy()
pthread_cont_wait() //線程解開mutex指向的鎖并被條件變量阻塞
pthread_cont_timedwait() //多了時間參數,當時間過了以后,即使條件變量不滿足,阻塞也被解除
pthread_cont_signal()/pthread_cont_broadcast //喚醒被條件變量阻塞的線程。
demo如下:
pthread1()
{
pthread_mutex_lock(lock_s);
sum++;
pthread_mutex_unlock(lock_s);
if (sum >= 100)
{
pthread_cond_signal(&cond_sum_ready);//先發送一次
}
}
pthread2()
{
pthread_mutex_lock(lock_s);
while(sum < 100)
{
pthread_cond_wait(&cond_sum_ready, &lock_s);//會先執行pthread_MUTEX_UNLOCK進行解鎖,然后休眠
}
sum = 0;
pthread_mutex_unlock(lock_s);
}
注意:最終哪個線程接收到信號,根據優先級來
4)讀寫鎖:可以多個線程同時占用讀模式的讀寫鎖,但是只能一個線程占用寫模式的讀寫鎖。
當讀寫鎖是寫加鎖狀態時,在這個鎖被解鎖前,所有試圖對這個鎖加鎖的線程都會被阻塞;
當讀寫鎖是讀加鎖狀態時,其他線程可以讀模式得到訪問權,但是以寫模式對它進行加鎖的線程都將被阻塞;
當讀寫鎖是在讀模式加鎖狀態時,如果有其他線程試圖以寫模式加鎖,讀寫鎖通常會阻塞隨后的讀模式鎖請求,避免讀模式鎖長期占用,而寫模式所長期阻塞;
讀寫鎖適用于對數據讀的次數比寫的次數多的情況。
API接口:
初始化和銷毀:
int pthread_rwlock_init();
int pthread rwlock_destroy();
讀加鎖、寫加鎖、解鎖:
pthread_rwlock_rdlock();
pthread_rwlock_wrlock();
pthread_rwlock_unlock();
非阻塞獲得讀鎖和寫鎖:
pthread_rwlock_tryrdlock();
pthread_rwlock_trywrlock();
demo如下
#include
#include
#include
?
#define Read_Num 2
?
pthread_rwlock_t lock;
?
class Data
{
public:
Data(int i, float f): I(i), F(f){}
int GetI()
{
return I;
}
?
float GetF()
{
return F;
}
?
private:
int I;
float F;
};
?
Data *pData = NULL;
?
void *read(void *arg)
{
int *id = (int*)arg;
while(true)
{
pthread_rwlock_rdlock(&lock);
printf(" reader %d is reading data\n", *id);
if (pData == NULL)
{
printf("data is NULL\n");
}
else
{
printf("data: I = %d, F = %f\n", pData->GetI(), pData->GetF());
}
pthread_rwlock_unlock(&lock);
}
pthread_exit(0);
}
?
void *write(void *arg)
{
while(true)
{
pthread_rwlock_wrlock(&lock); //寫鎖加鎖后,解鎖前,所有試圖對該鎖加鎖的線程都會被堵塞
printf("writer is wiriting data:\n");
if (pData == NULL)
{
pData = new Data(2, 2.2);
printf("writer is writing data: %d, %f\n", pData->GetI(), pData->GetF());
}
else
{
delete pData;
pData = NULL;
printf("wirter free the data\n");
}
pthread_rwlock_unlock(&lock);
?
}
pthread_exit(0);
}
?
int main()
{
pthread_t reader[Read_Num];
pthread_t writer;
for (int i = 0; i < Read_Num; i++)
{
pthread_create(&reader[i], NULL, read, (void*)&i);
}
pthread_create(&writer, NULL, write, NULL);
while(1)
{
sleep(1);
}
return 0;
}
2.信號量和互斥鎖之間的區別:
互斥鎖用于互斥,對資源的訪問是無序的,信號量用于同步,對資源的訪問是有序的
互斥量的加鎖和解鎖必須由同一線程對應使用,而信號量可以由一個線程釋放,另一個線程得到
3.什么情況下會產生死鎖以及怎樣避免死鎖
比如線程A,對資源M加鎖,去申請資源N;
線程B,對資源N加鎖,去申請資源M;
此種情況下會產生死鎖,要有效的避免死鎖,可使用銀行家算法:
線程A和B在使用資源的時候按照同一順序,即加鎖時按照同一順序,這樣就可以避免死鎖。
總結
以上是生活随笔為你收集整理的linux线程同步教程,多线程同步的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C指针原理(26)-gtk
- 下一篇: 案例 自动办公_办公自动化案例教程(双色