我正在嘗試學習如何在不使用全域變數的情況下使用執行緒更新某些共享記憶體,但是當我嘗試使用 strncpy 時,我不斷收到“分段錯誤(核心轉儲)”錯誤?
我試圖從每個執行緒的共享記憶體中參考唯一的資料結構?
任何提示將不勝感激!
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <string.h>
#define THREADCOUNT 3
#define ARRAYCOUNT 3
#define SHM_SIZE 48
#define KEY_NAME "test"
const int threadNumArray[3] = {0, 1, 2};
/* Data struct */
typedef struct struct_test
{
int testi; /* 4 bytes */
float testf; /* 4 bytes */
char testc[6]; /* 8 bytes (2 bytes padding) */
} test_t;
/* Arrays of data */
typedef struct shared_array_test
{
test_t test_array[ARRAYCOUNT];
} shm_array_t;
/* Pointer to arrays */
typedef struct shared_pointer_test
{
shm_array_t *array_ptr;
} shm_pointer_t;
/* Thread structs with pointer to data array and thread number */
typedef struct thread_array_test
{
int threadNum;
shm_pointer_t *shared_ptr;
} thread_array_t;
void *test_process(void *arg)
{
thread_array_t *thread_array = (void *)arg; /* Pointer to shared data */
test_t *test_data = &thread_array->shared_ptr->array_ptr->test_array[thread_array->threadNum]; /* Data from thread number */
char *testing = "TESTING"; /* String */
strncpy(test_data->testc, testing, 6); /* String copy to shared segement */
test_data->testf = 10.2; /* Assign float */
test_data->testi = 2; /* Test integer */
return NULL;
}
int main()
{
/* Create shared memory segement */
int shm_test;
shm_pointer_t *shared_test;
if ((shm_test = shm_open(KEY_NAME, O_CREAT | O_RDWR, 0666)) < 0)
{
printf("Error: shm_open");
return -1;
}
ftruncate(shm_test, SHM_SIZE);
if ((shared_test = mmap(0, SHM_SIZE, PROT_WRITE, MAP_SHARED, shm_test, 0)) == MAP_FAILED)
{
printf("Error: mmap");
return -1;
}
/* Creates structs for each thread */
thread_array_t thread_array[THREADCOUNT];
for (int i = 0; i < THREADCOUNT; i )
{
thread_array[i].shared_ptr = shared_test; /* Shared data */
thread_array[i].threadNum = threadNumArray[i]; /* Thread id */
}
/* Start threads */
pthread_t threads[THREADCOUNT];
for (int i = 0; i < THREADCOUNT; i )
{
pthread_create(&threads[i], NULL, test_process, thread_array i);
}
/* Join threads */
for (int i = 0; i < THREADCOUNT; i )
{
pthread_join(threads[i], NULL);
}
/* Test - Print strings */
for (int i = 0; i < THREADCOUNT; i )
{
printf("Test: %s", shared_test->array_ptr->test_array->testc);
}
return 0;
}
uj5u.com熱心網友回復:
初步注意,完全沒有必要設定POSIX共享記憶體段來在同一行程的執行緒之間共享資料。POSIX 共享記憶體主要用于允許不同的行程共享記憶體。同一行程的執行緒彼此運行在相同的地址空間中,并且它們自動可以訪問該空間的內容。事實上,這是執行緒的關鍵特性之一。
這樣一來,由于所有的typedefing 和不必要的包裝結構,您的代碼非常難以遵循。此外,基本上所有的名稱都非常缺乏資訊。隨著這一切的發生,您對自己感到困惑也就不足為奇了。
這里:
if ((shared_test = mmap(0, SHM_SIZE, PROT_WRITE, MAP_SHARED, shm_test, 0)) == MAP_FAILED)
...您將指向共享記憶體段的指標分配給shared_test型別為shm_pointer_t *aka 的變數struct shared_pointer_test *。該記憶體未初始化,特別shared_test->array_ptr是未分配指向任何內容。
您為所有執行緒提供shared_test指標的副本,并且它們嘗試使用它,就好像該array_ptr成員是有效指標一樣。這很可能是您的問題的根源,盡管還有其他可能具有類似可觀察影響的缺陷(見下文)。
此外,
- 對 使用數字常量無濟于事
SHM_SIZE,因為這無法了解如何選擇大小或記憶體的預期用途。使用sizeof代替整數常量。此外,因為它的使用是如此本地化,我認為制作一個宏實際上沒有幫助——沒有代碼會更清晰。 strncpy()如果在其第三個引數指定的字符數內沒有遇到一個空終止符,則不會添加空終止符。在您的情況下,testc如果程式實際到達該點,這將導致您的執行緒將未終止的字符陣列寫入各個成員。這本身并不是錯誤的,但是您不能將這些陣列視為字串,main()稍后會嘗試這樣做。strncat()通常比 更好的選擇strncpy(),即使前者可能需要通過在其第一個位置寫入終止符來準備目的地。- 您似乎對 POSIX 共享記憶體(您正在使用的)和 System V 共享記憶體之間至少有點困惑。具體來說,“
KEY_NAME”讓人想起 SysV IPC 密鑰,而 POSIX 共享記憶體物件只有名稱。這些名稱應以“/”開頭,而您的名稱則不是。 - 好的代碼注釋很有價值,但無用的代碼注釋比沒有注釋更糟糕。注釋應該解釋重要但不明顯的事情,例如實作選擇的原因、函式或代碼段的期望或前提條件,或類似的。
- 不要嘗試手動計算結構大小。它容易出錯且不可移植。相反,
sizeof在需要的地方使用計算物件和資料型別的大小。 main()通常應該回傳 0 - 125 范圍內的數字,而不是 -1perror可以很方便地發出有關庫函式呼叫失敗的錯誤訊息。- 雖然字面量
0是一個有效的空指標常量,但它是NULL用于此目的的更好形式,因為這使意圖更加清晰。 - 作為代碼風格的問題,避免包含不需要的標題。
這是您的代碼的一個變體,它洗掉了很多東西,改進了 (IMO) 大部分命名,并修復了大部分樣式問題。它比原來的更短更清晰,而且它也恰好可以正常作業。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#define THREADCOUNT 3
#define SHM_NAME "/test"
/* Data struct */
struct item {
int testi; /* 4 bytes */
float testf; /* 4 bytes */
char testc[6]; /* 8 bytes (2 bytes padding) */
};
/* The structure of the shared memory contents */
struct shared_data {
struct item test_array[THREADCOUNT];
};
/* Per-thread information */
struct thread_info {
int threadNum;
struct shared_data *shared_ptr;
};
void *test_process(void *arg) {
struct thread_info *my_info = arg;
struct item *test_data = &my_info->shared_ptr->test_array[my_info->threadNum];
test_data->testc[0] = '\0';
strncat(test_data->testc, "TESTING", sizeof(test_data->testc) - 1);
test_data->testf = 10.2;
test_data->testi = 2;
return NULL;
}
int main(void) {
/* Create shared memory segement */
int shm_test;
struct shared_data *shared;
if ((shm_test = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666)) < 0) {
perror("shm_open");
return 1;
}
ftruncate(shm_test, sizeof(*shared));
if ((shared = mmap(0, SHM_SIZE, PROT_WRITE, MAP_SHARED, shm_test, 0)) == MAP_FAILED) {
perror("mmap");
return 1;
}
/* Set up per-thread data */
struct thread_info thread_array[THREADCOUNT];
for (int i = 0; i < THREADCOUNT; i ) {
thread_array[i].shared_ptr = shared;
thread_array[i].threadNum = i;
}
/* Start threads */
pthread_t threads[THREADCOUNT];
for (int i = 0; i < THREADCOUNT; i ) {
pthread_create(&threads[i], NULL, test_process, thread_array i);
}
/* Join threads */
for (int i = 0; i < THREADCOUNT; i ) {
pthread_join(threads[i], NULL);
}
/* Test */
for (int i = 0; i < THREADCOUNT; i ) {
printf("Test: %s\n", shared->test_array[i].testc);
}
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/368925.html
上一篇:無法理解位移如下
下一篇:為什么這個c程式不能編譯階乘
