Pthread_mutex_lock возвращает ошибку доступа

Я пишу программу, которая читает и обрабатывает большие объемы данных. Чтобы ускорить процесс, я реализовал многопоточное чтение / обработку с использованием библиотеки Pthreads для C ++. Когда я вызываю pthread_mutex_lock (&lock1) на моем мьютексе, однако, моя программа выдает ошибку «ошибка доступа к месту чтения» по адресу lock1. Мне нужно было запустить эти потоки в методах класса, для чего потребовалось некоторое маневрирование в рамках ограничений библиотеки pthread, и где-то в этом маневрировании я допустил ошибку. Ниже приведена сокращенная версия моего кода, извините за tl; dr. Сократите его настолько, насколько это возможно, не оставляя каких-либо разделов, важных для многопоточности:

#include "pthread.h"#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <Windows.h>/*Ideally I need to create one instance of this object that has the run_stuff method
being executed by two different threads.  I need both threads to have access to the
same private variables, and have ensured that those variables won't be accessed at the
same time. That is the end goal of my multithreading*/

class test_obj {
public:
test_obj();
void run_stuff(int); //the method I want to run on two different threads using the same private variables
private:
int count;
void switch_gate1();//switches the value of gate 1
void switch_gate2();
bool test_gate1(int); //checks to see if gate 1 equals thread id
bool test_gate2(int);
bool gate1, gate2; //can only be accessed under a locked mutex
pthread_mutex_t lock1, lock2;
};

/*This structure is what I pass to pthread_create*/
struct thread_args { //arguements passed to a thread when it is created
thread_args() {a = new test_obj;}; //constructor: create new test_obj instance
test_obj *a; //pointer to a test_obj instance, I think both threads receive a pointer to the same instance
int t_id; //ID of thread being created
};

class thread_helper { //managing function to create threads and call run_stuff method
public:
thread_helper() {args = new thread_args;};
void my_method(); //called from main, creates threads and runs them
private:
thread_args *args; //pointer to a thread_args obj
static void* execute(void *ptr); //method to be run by created threads
pthread_t m_thread1, m_thread2; //the two threads
};

int main() {
thread_helper c;
c.my_method();
return 0;
}

test_obj::test_obj() {
count = 0; //not important right now, test variable
gate1 = 0; //thread 0 gets first access
gate2 = 0; //thread 0 gets first access
}

void thread_helper::my_method() {
int error_code;
thread_args *a, *b;
*a = *b = *args;
a->t_id = 0;
b->t_id = 1;
error_code = pthread_create(&m_thread1, NULL, &thread_helper::execute, (void*)a); //create thread 0 to run execute method
assert(0 == error_code); //check for success
error_code = pthread_create(&m_thread2, NULL, &thread_helper::execute, (void*)b);
assert(0 == error_code);
error_code = pthread_join(m_thread1, NULL);//wait for thread 0
assert(0 == error_code);
error_code = pthread_join(m_thread2, NULL); //wait for thread 1
assert(0 == error_code);
}

void* thread_helper::execute(void *ptr) {
thread_args *b = (thread_args*)ptr;//recast ptr back into thread_args type
int t_id = b->t_id;//save thread id
b->a->run_stuff(t_id);//access test_obj object from thread_args (should be same object for both threads) and run method
return NULL;
}

void test_obj::run_stuff(int t_id) {
for(int i = 0; i < 2; i++) { //run twice (give a chance for threads to flip flop)
//-----Part 1
while(!test_gate1(t_id)){//while not allowed to proceed
Sleep(500);//sleep
}
printf("thread %d reporting in\n", t_id);//thread has gained access to part 1, print id
switch_gate1();//allow opposite thread in
//-----Part 2
while(!test_gate2(t_id)){//wait for access to part 2
Sleep(500);
}
//count++; //just a dummy place for now, will be used later to check access
switch_gate2();//allow opposite thread in
}
}

bool test_obj::test_gate1(int t_id) {//returns true if id of calling thread matches value of gate 1
//a return value of true means a thread is allowed to proceed, false otherwise
pthread_mutex_lock(&lock1);**//secure access to gate THIS IS WHAT ERRORS OUT**
if(t_id == gate1){//check gate
pthread_mutex_unlock(&lock1);//release gate
return true;//return
}
else {
pthread_mutex_unlock(&lock1);
return false;
}
}

bool test_obj::test_gate2(int t_id) {
pthread_mutex_lock(&lock2);
if(t_id == gate2){
pthread_mutex_unlock(&lock2);
return true;
}
else {
pthread_mutex_unlock(&lock2);
return false;
}
}

/*Switch gate functions are designed to obtain access to the boolean gate (prevent the opposing thread from checking the gate by means of mutex), then switch the value of the boolean gate and release the gate for the other thread to check.*/
void test_obj::switch_gate1() {
pthread_mutex_lock(&lock1);//secure access to gate
gate1 = !gate1; //flip gate
pthread_mutex_unlock(&lock1); //release gate
}

void test_obj::switch_gate2() {
pthread_mutex_lock(&lock2);
gate2 = !gate2;
pthread_mutex_unlock(&lock2);
}

Извините за форматирование. У кого-нибудь есть идеи, почему в этой блокировке могут быть ошибки нарушения доступа? Я пытался повсюду. Частный, публичный и даже глобальный в крайнем случае. Все они дают одинаковую ошибку. Заранее спасибо.

РЕДАКТИРОВАТЬ: Исправлена ​​ошибка при передаче моей переменной thread_args в pthreads_create. Работает, как и ожидалось, после этого и исправления инициализации / уничтожения.

3

Решение

Вы, кажется, не инициализируете свои мьютексы. Я не вижу, где у вас есть объявления ваших мьютексов.

Объявите переменные в вашем test_obj:

pthread_mutex_t lock1;
pthread_mutex_t lock2;

Добавьте это к вашему test_obj конструктор:

test_obj::test_obj() {
...
lock1 = PTHREAD_MUTEX_INITIALIZER;
lock2 = PTHREAD_MUTEX_INITIALIZER;
}

Добавьте это к test_obj деструктор:

test_obj::~test_obj() {
pthread_mutex_destroy(&lock1);
pthread_mutex_destroy(&lock2);
}
5

Другие решения

Других решений пока нет …